Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`.  (3.4ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL PRIMARY KEY)  (0.2ms) 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::SchemaMigration Load (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::InternalMetadata Load (0.6ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "environment"]] ActiveRecord::InternalMetadata Create (5.2ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ('environment', 'test', '2025-11-20 17:13:54.117520', '2025-11-20 17:13:54.117523') RETURNING "key" ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC Migrating to CreateBreakEscapeMissions (20251120155357) TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.6ms) 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 FALSE NOT NULL, "difficulty_level" integer DEFAULT 1 NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL)  (0.1ms) CREATE UNIQUE INDEX "index_break_escape_missions_on_name" ON "break_escape_missions" ("name")  (0.1ms) CREATE INDEX "index_break_escape_missions_on_published" ON "break_escape_missions" ("published") ActiveRecord::SchemaMigration Create (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES ('20251120155357') RETURNING "version" TRANSACTION (0.1ms) COMMIT TRANSACTION Migrating to CreateBreakEscapeGames (20251120155358) Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::SchemaMigration Load (0.4ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC ActiveRecord::InternalMetadata Load (0.2ms) 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.1ms) 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.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC 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, "environment"]] 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, "environment"]] ActiveRecord::SchemaMigration Load (0.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC Migrating to CreateBreakEscapeGames (20251120155358) TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.4ms) 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.1ms) CREATE INDEX "index_break_escape_games_on_player" ON "break_escape_games" ("player_type", "player_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_mission_id" ON "break_escape_games" ("mission_id")  (0.1ms) CREATE UNIQUE INDEX "index_games_on_player_and_mission" ON "break_escape_games" ("player_type", "player_id", "mission_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_status" ON "break_escape_games" ("status") ActiveRecord::SchemaMigration Create (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES ('20251120155358') RETURNING "version" TRANSACTION (5.3ms) COMMIT TRANSACTION Migrating to CreateBreakEscapeDemoUsers (20251120160000) TRANSACTION (0.0ms) BEGIN immediate TRANSACTION  (0.3ms) 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.2ms) CREATE UNIQUE INDEX "index_break_escape_demo_users_on_handle" ON "break_escape_demo_users" ("handle") ActiveRecord::SchemaMigration Create (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES ('20251120160000') RETURNING "version" TRANSACTION (0.1ms) COMMIT TRANSACTION ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`.  (1.2ms) DROP TABLE IF EXISTS "break_escape_demo_users"  (3.7ms) CREATE TABLE "break_escape_demo_users" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime(6) NOT NULL, "handle" varchar NOT NULL, "role" varchar DEFAULT 'user' NOT NULL, "updated_at" datetime(6) NOT NULL)  (0.2ms) CREATE UNIQUE INDEX "index_break_escape_demo_users_on_handle" ON "break_escape_demo_users" ("handle")  (0.1ms) DROP TABLE IF EXISTS "break_escape_games"  (0.3ms) CREATE TABLE "break_escape_games" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "completed_at" datetime(6), "created_at" datetime(6) NOT NULL, "mission_id" integer NOT NULL, "player_id" integer NOT NULL, "player_state" json DEFAULT '"{\"currentRoom\":null,\"unlockedRooms\":[],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"' NOT NULL, "player_type" varchar NOT NULL, "scenario_data" json NOT NULL, "score" integer DEFAULT 0 NOT NULL, "started_at" datetime(6), "status" varchar DEFAULT 'in_progress' NOT NULL, "updated_at" datetime(6) NOT NULL)  (0.2ms) CREATE INDEX "index_break_escape_games_on_mission_id" ON "break_escape_games" ("mission_id")  (0.3ms) CREATE UNIQUE INDEX "index_games_on_player_and_mission" ON "break_escape_games" ("player_type", "player_id", "mission_id")  (0.2ms) CREATE INDEX "index_break_escape_games_on_player" ON "break_escape_games" ("player_type", "player_id")  (0.2ms) CREATE INDEX "index_break_escape_games_on_status" ON "break_escape_games" ("status")  (0.1ms) DROP TABLE IF EXISTS "break_escape_missions"  (0.3ms) CREATE TABLE "break_escape_missions" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime(6) NOT NULL, "description" text, "difficulty_level" integer DEFAULT 1 NOT NULL, "display_name" varchar NOT NULL, "name" varchar NOT NULL, "published" boolean DEFAULT FALSE NOT NULL, "updated_at" datetime(6) NOT NULL)  (0.3ms) CREATE UNIQUE INDEX "index_break_escape_missions_on_name" ON "break_escape_missions" ("name")  (0.2ms) CREATE INDEX "index_break_escape_missions_on_published" ON "break_escape_missions" ("published")  (0.1ms) PRAGMA foreign_keys  (0.0ms) PRAGMA defer_foreign_keys  (0.0ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.2ms) CREATE TEMPORARY TABLE "abreak_escape_games" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "completed_at" datetime(6), "created_at" datetime(6) NOT NULL, "mission_id" integer NOT NULL, "player_id" integer NOT NULL, "player_state" json DEFAULT '"{\"currentRoom\":null,\"unlockedRooms\":[],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"' NOT NULL, "player_type" varchar NOT NULL, "scenario_data" json NOT NULL, "score" integer DEFAULT 0 NOT NULL, "started_at" datetime(6), "status" varchar DEFAULT 'in_progress' NOT NULL, "updated_at" datetime(6) NOT NULL)  (0.1ms) CREATE INDEX "tindex_abreak_escape_games_on_status" ON "abreak_escape_games" ("status")  (0.1ms) CREATE INDEX "tindex_abreak_escape_games_on_player" ON "abreak_escape_games" ("player_type", "player_id")  (0.1ms) CREATE UNIQUE INDEX "tindex_games_on_player_and_mission" ON "abreak_escape_games" ("player_type", "player_id", "mission_id")  (0.1ms) CREATE INDEX "tindex_abreak_escape_games_on_mission_id" ON "abreak_escape_games" ("mission_id") SQL (0.4ms) INSERT INTO "abreak_escape_games" ("id","completed_at","created_at","mission_id","player_id","player_state","player_type","scenario_data","score","started_at","status","updated_at") SELECT "id","completed_at","created_at","mission_id","player_id","player_state","player_type","scenario_data","score","started_at","status","updated_at" FROM "break_escape_games"  (0.4ms) DROP TABLE "break_escape_games"  (0.2ms) CREATE TABLE "break_escape_games" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "completed_at" datetime(6), "created_at" datetime(6) NOT NULL, "mission_id" integer NOT NULL, "player_id" integer NOT NULL, "player_state" json DEFAULT '"{\"currentRoom\":null,\"unlockedRooms\":[],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"' NOT NULL, "player_type" varchar NOT NULL, "scenario_data" json NOT NULL, "score" integer DEFAULT 0 NOT NULL, "started_at" datetime(6), "status" varchar DEFAULT 'in_progress' NOT NULL, "updated_at" datetime(6) NOT NULL, CONSTRAINT "fk_rails_ce758a8dd4" FOREIGN KEY ("mission_id") REFERENCES "break_escape_missions" ("id") )  (0.1ms) CREATE INDEX "index_break_escape_games_on_mission_id" ON "break_escape_games" ("mission_id")  (0.1ms) CREATE UNIQUE INDEX "index_games_on_player_and_mission" ON "break_escape_games" ("player_type", "player_id", "mission_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_player" ON "break_escape_games" ("player_type", "player_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_status" ON "break_escape_games" ("status") SQL (0.1ms) INSERT INTO "break_escape_games" ("id","completed_at","created_at","mission_id","player_id","player_state","player_type","scenario_data","score","started_at","status","updated_at") SELECT "id","completed_at","created_at","mission_id","player_id","player_state","player_type","scenario_data","score","started_at","status","updated_at" FROM "abreak_escape_games"  (0.2ms) DROP TABLE "abreak_escape_games" TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1  (0.2ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL PRIMARY KEY) ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC  (0.2ms) INSERT INTO "schema_migrations" (version) VALUES (20251120160000)  (0.1ms) INSERT INTO "schema_migrations" (version) VALUES (20251120155358), (20251120155357);  (0.3ms) 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.1ms) 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.3ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ('environment', 'test', '2025-11-20 17:15:26.896212', '2025-11-20 17:15:26.896218') RETURNING "key" 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, "environment"]] 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::InternalMetadata Create (0.3ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ('schema_sha1', '33181f3d58f9bab484a9b348ce1e6b298e81ba9b', '2025-11-20 17:15:26.897909', '2025-11-20 17:15:26.897911') RETURNING "key" ActiveRecord::SchemaMigration Load (0.6ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.5ms) 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.4ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (149617800, '2025-11-20 17:15:27.433387', 'test_user', 'user', '2025-11-20 17:15:27.433387'), (618102942, '2025-11-20 17:15:27.433387', 'other_user', 'user', '2025-11-20 17:15:27.433387'); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (223060831, NULL, '2025-11-20 17:15:27.438207', 418560898, 149617800, '{"currentRoom":"reception","unlockedRooms":["reception"]}', 'BreakEscape::DemoUser', '{"startRoom":"reception","rooms":{}}', 0, NULL, 'in_progress', '2025-11-20 17:15:27.438207'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (418560898, '2025-11-20 17:15:27.442020', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:15:27.442020'), (636030761, '2025-11-20 17:15:27.442020', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:15:27.442020')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.9ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_presence_of_name --------------------------------------------------------------- BreakEscape::Mission Exists? (0.3ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ------------------------------------------------------------------------------ BreakEscape::MissionTest: test_published_scope_returns_only_published_missions ------------------------------------------------------------------------------ TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::MissionTest: test_scenario_path_returns_correct_path ----------------------------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_uniqueness_of_name ----------------------------------------------------------------- TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Exists? (0.4ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] BreakEscape::Mission Create (0.4ms) INSERT INTO "break_escape_missions" ("created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["created_at", "2025-11-20 17:15:27.595654"], ["description", nil], ["difficulty_level", 1], ["display_name", "Test"], ["name", "test"], ["published", 0], ["updated_at", "2025-11-20 17:15:27.595654"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 BreakEscape::Mission Exists? (1.8ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------- BreakEscapeTest: test_it_has_a_version_number --------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ---------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-20 17:15:27 +0000 Processing by BreakEscape::MissionsController#index as HTML Completed 500 Internal Server Error in 7ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_show_published_mission ----------------------------------------------------------------------- BreakEscape::Mission Load (0.3ms) 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-20 17:15:28 +0000 Processing by BreakEscape::MissionsController#show as HTML Parameters: {"id"=>"418560898"} BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] Completed 500 Internal Server Error in 14ms (ActiveRecord: 0.1ms (1 query, 0 cached) | GC: 10.0ms) TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ------------------------------------------------ BreakEscape::GameTest: test_should_update_health ------------------------------------------------ TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------------------------- BreakEscape::GameTest: test_should_belong_to_player_and_mission --------------------------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.0ms) BEGIN deferred TRANSACTION -------------------------------------------------- BreakEscape::GameTest: test_should_track_inventory -------------------------------------------------- TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.0ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 ----------------------------------------------------------------- TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.0ms) BEGIN deferred TRANSACTION ---------------------------------------------- BreakEscape::GameTest: test_should_unlock_room ---------------------------------------------- TRANSACTION (0.0ms) ROLLBACK TRANSACTION Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::InternalMetadata Load (0.4ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::InternalMetadata Load (0.6ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::InternalMetadata Load (0.6ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.4ms) PRAGMA foreign_keys  (0.0ms) PRAGMA defer_foreign_keys  (0.1ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.3ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, NULL, 'test_user', 'user', NULL), (NULL, NULL, 'other_user', 'user', NULL); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, NULL, 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, NULL, 'in_progress', NULL); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, NULL, 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, NULL), (NULL, NULL, 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, NULL)  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.5ms) PRAGMA foreign_keys  (0.1ms) PRAGMA defer_foreign_keys  (0.1ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.3ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, NULL, 'test_user', 'user', NULL), (NULL, NULL, 'other_user', 'user', NULL); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, NULL, 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, NULL, 'in_progress', NULL); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, NULL, 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, NULL), (NULL, NULL, 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, NULL)  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.5ms) 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.3ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, NULL, 'test_user', 'user', NULL), (NULL, NULL, 'other_user', 'user', NULL); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, NULL, 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, NULL, 'in_progress', NULL); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, NULL, 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, NULL), (NULL, NULL, 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, NULL)  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, NULL, 'test_user', 'user', NULL), (NULL, NULL, 'other_user', 'user', NULL); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, NULL, 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, NULL, 'in_progress', NULL); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, NULL, 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, NULL), (NULL, NULL, 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, NULL)  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, NULL, 'test_user', 'user', NULL), (NULL, NULL, 'other_user', 'user', NULL); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, NULL, 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, NULL, 'in_progress', NULL); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, NULL, 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, NULL), (NULL, NULL, 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, NULL)  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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.3ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, NULL, 'test_user', 'user', NULL), (NULL, NULL, 'other_user', 'user', NULL); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, NULL, 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, NULL, 'in_progress', NULL); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, NULL, 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, NULL), (NULL, NULL, 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, NULL)  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.2ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, NULL, 'test_user', 'user', NULL), (NULL, NULL, 'other_user', 'user', NULL); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, NULL, 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, NULL, 'in_progress', NULL); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, NULL, 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, NULL), (NULL, NULL, 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, NULL)  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.2ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, NULL, 'test_user', 'user', NULL), (NULL, NULL, 'other_user', 'user', NULL); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, NULL, 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, NULL, 'in_progress', NULL); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, NULL, 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, NULL), (NULL, NULL, 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, NULL)  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, NULL, 'test_user', 'user', NULL), (NULL, NULL, 'other_user', 'user', NULL); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, NULL, 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, NULL, 'in_progress', NULL); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, NULL, 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, NULL), (NULL, NULL, 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, NULL)  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.2ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, NULL, 'test_user', 'user', NULL), (NULL, NULL, 'other_user', 'user', NULL); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, NULL, 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, NULL, 'in_progress', NULL); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, NULL, 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, NULL), (NULL, NULL, 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, NULL)  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, NULL, 'test_user', 'user', NULL), (NULL, NULL, 'other_user', 'user', NULL); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, NULL, 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, NULL, 'in_progress', NULL); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, NULL, 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, NULL), (NULL, NULL, 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, NULL)  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, NULL, 'test_user', 'user', NULL), (NULL, NULL, 'other_user', 'user', NULL); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, NULL, 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, NULL, 'in_progress', NULL); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, NULL, 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, NULL), (NULL, NULL, 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, NULL)  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.0ms) ROLLBACK TRANSACTION Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::InternalMetadata Load (0.6ms) 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.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.4ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'test_user', 'user', '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'other_user', 'user', '2025-11-20 17:20:11'); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, '2025-11-20 17:20:11', 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, '2025-11-20 17:20:11', 'in_progress', '2025-11-20 17:20:11'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:20:11')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (5.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.4ms) PRAGMA foreign_keys  (0.0ms) PRAGMA defer_foreign_keys  (0.0ms) PRAGMA defer_foreign_keys = ON  (0.1ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'test_user', 'user', '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'other_user', 'user', '2025-11-20 17:20:11'); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, '2025-11-20 17:20:11', 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, '2025-11-20 17:20:11', 'in_progress', '2025-11-20 17:20:11'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:20:11')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'test_user', 'user', '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'other_user', 'user', '2025-11-20 17:20:11'); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, '2025-11-20 17:20:11', 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, '2025-11-20 17:20:11', 'in_progress', '2025-11-20 17:20:11'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:20:11')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.4ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'test_user', 'user', '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'other_user', 'user', '2025-11-20 17:20:11'); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, '2025-11-20 17:20:11', 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, '2025-11-20 17:20:11', 'in_progress', '2025-11-20 17:20:11'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:20:11')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.5ms) PRAGMA foreign_keys  (0.1ms) PRAGMA defer_foreign_keys  (0.1ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'test_user', 'user', '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'other_user', 'user', '2025-11-20 17:20:11'); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, '2025-11-20 17:20:11', 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, '2025-11-20 17:20:11', 'in_progress', '2025-11-20 17:20:11'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:20:11')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.4ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'test_user', 'user', '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'other_user', 'user', '2025-11-20 17:20:11'); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, '2025-11-20 17:20:11', 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, '2025-11-20 17:20:11', 'in_progress', '2025-11-20 17:20:11'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:20:11')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.2ms) BEGIN immediate TRANSACTION  (0.5ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'test_user', 'user', '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'other_user', 'user', '2025-11-20 17:20:11'); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, '2025-11-20 17:20:11', 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, '2025-11-20 17:20:11', 'in_progress', '2025-11-20 17:20:11'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:20:11')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'test_user', 'user', '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'other_user', 'user', '2025-11-20 17:20:11'); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, '2025-11-20 17:20:11', 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, '2025-11-20 17:20:11', 'in_progress', '2025-11-20 17:20:11'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:20:11')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'test_user', 'user', '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'other_user', 'user', '2025-11-20 17:20:11'); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, '2025-11-20 17:20:11', 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, '2025-11-20 17:20:11', 'in_progress', '2025-11-20 17:20:11'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:20:11')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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.4ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'test_user', 'user', '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'other_user', 'user', '2025-11-20 17:20:11'); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, '2025-11-20 17:20:11', 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, '2025-11-20 17:20:11', 'in_progress', '2025-11-20 17:20:11'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:20:11')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'test_user', 'user', '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'other_user', 'user', '2025-11-20 17:20:11'); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, '2025-11-20 17:20:11', 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, '2025-11-20 17:20:11', 'in_progress', '2025-11-20 17:20:11'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:20:11')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.4ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_games"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'test_user', 'user', '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'other_user', 'user', '2025-11-20 17:20:11'); INSERT INTO "break_escape_games" ("id", "completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (NULL, NULL, '2025-11-20 17:20:11', 418560898, 149617800, '"{\"currentRoom\": \"reception\", \"unlockedRooms\": [\"reception\"], \"unlockedObjects\": [], \"inventory\": [], \"encounteredNPCs\": [], \"globalVariables\": {}, \"biometricSamples\": [], \"biometricUnlocks\": [], \"bluetoothDevices\": [], \"notes\": [], \"health\": 100}"', 'BreakEscape::DemoUser', '"{\"startRoom\": \"reception\", \"rooms\": {}}"', 0, '2025-11-20 17:20:11', 'in_progress', '2025-11-20 17:20:11'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:20:11', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:20:11'), (NULL, '2025-11-20 17:20:11', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:20:11')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.5ms) PRAGMA foreign_keys  (0.0ms) PRAGMA defer_foreign_keys  (0.1ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:21:12', 'test_user', 'user', '2025-11-20 17:21:12'), (NULL, '2025-11-20 17:21:12', 'other_user', 'user', '2025-11-20 17:21:12'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:21:12', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:21:12'), (NULL, '2025-11-20 17:21:12', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:21:12')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (5.0ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.4ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'test_user', 'user', '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'other_user', 'user', '2025-11-20 17:21:13'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:21:13')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.4ms) PRAGMA foreign_keys  (0.1ms) PRAGMA defer_foreign_keys  (0.0ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'test_user', 'user', '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'other_user', 'user', '2025-11-20 17:21:13'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:21:13')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.2ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'test_user', 'user', '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'other_user', 'user', '2025-11-20 17:21:13'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:21:13')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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.3ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'test_user', 'user', '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'other_user', 'user', '2025-11-20 17:21:13'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:21:13')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.2ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'test_user', 'user', '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'other_user', 'user', '2025-11-20 17:21:13'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:21:13')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.2ms) 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.3ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'test_user', 'user', '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'other_user', 'user', '2025-11-20 17:21:13'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:21:13')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.2ms) 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", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'test_user', 'user', '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'other_user', 'user', '2025-11-20 17:21:13'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:21:13')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.2ms) PRAGMA foreign_keys  (0.0ms) PRAGMA defer_foreign_keys  (0.0ms) PRAGMA defer_foreign_keys = ON  (0.1ms) 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", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'test_user', 'user', '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'other_user', 'user', '2025-11-20 17:21:13'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:21:13')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.2ms) 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", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'test_user', 'user', '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'other_user', 'user', '2025-11-20 17:21:13'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:21:13')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.2ms) 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.3ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'test_user', 'user', '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'other_user', 'user', '2025-11-20 17:21:13'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:21:13')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.0ms) BEGIN immediate TRANSACTION  (0.2ms) 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", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'test_user', 'user', '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'other_user', 'user', '2025-11-20 17:21:13'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:21:13', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:21:13'), (NULL, '2025-11-20 17:21:13', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:21:13')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::InternalMetadata Load (0.6ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:22:17', 'test_user', 'user', '2025-11-20 17:22:17'), (NULL, '2025-11-20 17:22:17', 'other_user', 'user', '2025-11-20 17:22:17'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:22:17', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:22:17'), (NULL, '2025-11-20 17:22:17', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:22:17')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (5.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:22:17', 'test_user', 'user', '2025-11-20 17:22:17'), (NULL, '2025-11-20 17:22:17', 'other_user', 'user', '2025-11-20 17:22:17'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:22:17', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:22:17'), (NULL, '2025-11-20 17:22:17', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:22:17')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) PRAGMA foreign_keys  (0.1ms) 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", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:22:17', 'test_user', 'user', '2025-11-20 17:22:17'), (NULL, '2025-11-20 17:22:17', 'other_user', 'user', '2025-11-20 17:22:17'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:22:17', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:22:17'), (NULL, '2025-11-20 17:22:17', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:22:17')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.0ms) BEGIN immediate TRANSACTION  (0.2ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:22:17', 'test_user', 'user', '2025-11-20 17:22:17'), (NULL, '2025-11-20 17:22:17', 'other_user', 'user', '2025-11-20 17:22:17'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:22:17', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:22:17'), (NULL, '2025-11-20 17:22:17', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:22:17')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.4ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:22:17', 'test_user', 'user', '2025-11-20 17:22:17'), (NULL, '2025-11-20 17:22:17', 'other_user', 'user', '2025-11-20 17:22:17'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:22:17', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:22:17'), (NULL, '2025-11-20 17:22:17', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:22:17')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.1ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.4ms) PRAGMA foreign_keys  (0.0ms) PRAGMA defer_foreign_keys  (0.0ms) PRAGMA defer_foreign_keys = ON  (0.1ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:22:18', 'test_user', 'user', '2025-11-20 17:22:18'), (NULL, '2025-11-20 17:22:18', 'other_user', 'user', '2025-11-20 17:22:18'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:22:18', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:22:18'), (NULL, '2025-11-20 17:22:18', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:22:18')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.1ms) PRAGMA foreign_keys = 1 TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:22:18', 'test_user', 'user', '2025-11-20 17:22:18'), (NULL, '2025-11-20 17:22:18', 'other_user', 'user', '2025-11-20 17:22:18'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:22:18', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:22:18'), (NULL, '2025-11-20 17:22:18', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:22:18')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.2ms) 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.4ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:22:18', 'test_user', 'user', '2025-11-20 17:22:18'), (NULL, '2025-11-20 17:22:18', 'other_user', 'user', '2025-11-20 17:22:18'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:22:18', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:22:18'), (NULL, '2025-11-20 17:22:18', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:22:18')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.2ms) 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", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:22:18', 'test_user', 'user', '2025-11-20 17:22:18'), (NULL, '2025-11-20 17:22:18', 'other_user', 'user', '2025-11-20 17:22:18'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:22:18', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:22:18'), (NULL, '2025-11-20 17:22:18', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:22:18')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:22:18', 'test_user', 'user', '2025-11-20 17:22:18'), (NULL, '2025-11-20 17:22:18', 'other_user', 'user', '2025-11-20 17:22:18'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:22:18', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:22:18'), (NULL, '2025-11-20 17:22:18', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:22:18')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.2ms) 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", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:22:18', 'test_user', 'user', '2025-11-20 17:22:18'), (NULL, '2025-11-20 17:22:18', 'other_user', 'user', '2025-11-20 17:22:18'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:22:18', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:22:18'), (NULL, '2025-11-20 17:22:18', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:22:18')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:22:18', 'test_user', 'user', '2025-11-20 17:22:18'), (NULL, '2025-11-20 17:22:18', 'other_user', 'user', '2025-11-20 17:22:18'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:22:18', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:22:18'), (NULL, '2025-11-20 17:22:18', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:22:18')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::SchemaMigration Load (0.5ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC ActiveRecord::InternalMetadata Load (0.2ms) 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.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC 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, "environment"]] ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC 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, "environment"]]  (4.9ms) DROP TABLE IF EXISTS "break_escape_demo_users"  (0.2ms) CREATE TABLE "break_escape_demo_users" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime(6) NOT NULL, "handle" varchar NOT NULL, "role" varchar DEFAULT 'user' NOT NULL, "updated_at" datetime(6) NOT NULL)  (0.2ms) CREATE UNIQUE INDEX "index_break_escape_demo_users_on_handle" ON "break_escape_demo_users" ("handle")  (0.4ms) DROP TABLE IF EXISTS "break_escape_games"  (0.2ms) CREATE TABLE "break_escape_games" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "completed_at" datetime(6), "created_at" datetime(6) NOT NULL, "mission_id" integer NOT NULL, "player_id" integer NOT NULL, "player_state" json DEFAULT '"{\"currentRoom\":null,\"unlockedRooms\":[],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"' NOT NULL, "player_type" varchar NOT NULL, "scenario_data" json NOT NULL, "score" integer DEFAULT 0 NOT NULL, "started_at" datetime(6), "status" varchar DEFAULT 'in_progress' NOT NULL, "updated_at" datetime(6) NOT NULL)  (0.1ms) CREATE INDEX "index_break_escape_games_on_mission_id" ON "break_escape_games" ("mission_id")  (0.1ms) CREATE UNIQUE INDEX "index_games_on_player_and_mission" ON "break_escape_games" ("player_type", "player_id", "mission_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_player" ON "break_escape_games" ("player_type", "player_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_status" ON "break_escape_games" ("status")  (0.2ms) DROP TABLE IF EXISTS "break_escape_missions"  (0.2ms) CREATE TABLE "break_escape_missions" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime(6) NOT NULL, "description" text, "difficulty_level" integer DEFAULT 1 NOT NULL, "display_name" varchar NOT NULL, "name" varchar NOT NULL, "published" boolean DEFAULT FALSE NOT NULL, "updated_at" datetime(6) NOT NULL)  (0.1ms) CREATE UNIQUE INDEX "index_break_escape_missions_on_name" ON "break_escape_missions" ("name")  (0.1ms) CREATE INDEX "index_break_escape_missions_on_published" ON "break_escape_missions" ("published")  (0.1ms) 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 immediate TRANSACTION  (0.2ms) CREATE TEMPORARY TABLE "abreak_escape_games" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "completed_at" datetime(6), "created_at" datetime(6) NOT NULL, "mission_id" integer NOT NULL, "player_id" integer NOT NULL, "player_state" json DEFAULT '"{\"currentRoom\":null,\"unlockedRooms\":[],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"' NOT NULL, "player_type" varchar NOT NULL, "scenario_data" json NOT NULL, "score" integer DEFAULT 0 NOT NULL, "started_at" datetime(6), "status" varchar DEFAULT 'in_progress' NOT NULL, "updated_at" datetime(6) NOT NULL)  (0.1ms) CREATE INDEX "tindex_abreak_escape_games_on_status" ON "abreak_escape_games" ("status")  (0.1ms) CREATE INDEX "tindex_abreak_escape_games_on_player" ON "abreak_escape_games" ("player_type", "player_id")  (0.1ms) CREATE UNIQUE INDEX "tindex_games_on_player_and_mission" ON "abreak_escape_games" ("player_type", "player_id", "mission_id")  (0.1ms) CREATE INDEX "tindex_abreak_escape_games_on_mission_id" ON "abreak_escape_games" ("mission_id") SQL (0.1ms) INSERT INTO "abreak_escape_games" ("id","completed_at","created_at","mission_id","player_id","player_state","player_type","scenario_data","score","started_at","status","updated_at") SELECT "id","completed_at","created_at","mission_id","player_id","player_state","player_type","scenario_data","score","started_at","status","updated_at" FROM "break_escape_games"  (0.2ms) DROP TABLE "break_escape_games"  (0.1ms) CREATE TABLE "break_escape_games" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "completed_at" datetime(6), "created_at" datetime(6) NOT NULL, "mission_id" integer NOT NULL, "player_id" integer NOT NULL, "player_state" json DEFAULT '"{\"currentRoom\":null,\"unlockedRooms\":[],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"' NOT NULL, "player_type" varchar NOT NULL, "scenario_data" json NOT NULL, "score" integer DEFAULT 0 NOT NULL, "started_at" datetime(6), "status" varchar DEFAULT 'in_progress' NOT NULL, "updated_at" datetime(6) NOT NULL, CONSTRAINT "fk_rails_ce758a8dd4" FOREIGN KEY ("mission_id") REFERENCES "break_escape_missions" ("id") )  (0.1ms) CREATE INDEX "index_break_escape_games_on_mission_id" ON "break_escape_games" ("mission_id")  (0.1ms) CREATE UNIQUE INDEX "index_games_on_player_and_mission" ON "break_escape_games" ("player_type", "player_id", "mission_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_player" ON "break_escape_games" ("player_type", "player_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_status" ON "break_escape_games" ("status") SQL (0.1ms) INSERT INTO "break_escape_games" ("id","completed_at","created_at","mission_id","player_id","player_state","player_type","scenario_data","score","started_at","status","updated_at") SELECT "id","completed_at","created_at","mission_id","player_id","player_state","player_type","scenario_data","score","started_at","status","updated_at" FROM "abreak_escape_games"  (0.1ms) DROP TABLE "abreak_escape_games" TRANSACTION (0.2ms) COMMIT TRANSACTION  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC 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, "environment"]] 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, "environment"]] 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 Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`.  (1.1ms) DROP TABLE IF EXISTS "break_escape_demo_users"  (3.7ms) CREATE TABLE "break_escape_demo_users" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime(6) NOT NULL, "handle" varchar NOT NULL, "role" varchar DEFAULT 'user' NOT NULL, "updated_at" datetime(6) NOT NULL)  (0.2ms) CREATE UNIQUE INDEX "index_break_escape_demo_users_on_handle" ON "break_escape_demo_users" ("handle")  (0.1ms) DROP TABLE IF EXISTS "break_escape_games"  (0.2ms) CREATE TABLE "break_escape_games" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "completed_at" datetime(6), "created_at" datetime(6) NOT NULL, "mission_id" integer NOT NULL, "player_id" integer NOT NULL, "player_state" json DEFAULT '"{\"currentRoom\":null,\"unlockedRooms\":[],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"' NOT NULL, "player_type" varchar NOT NULL, "scenario_data" json NOT NULL, "score" integer DEFAULT 0 NOT NULL, "started_at" datetime(6), "status" varchar DEFAULT 'in_progress' NOT NULL, "updated_at" datetime(6) NOT NULL)  (0.1ms) CREATE INDEX "index_break_escape_games_on_mission_id" ON "break_escape_games" ("mission_id")  (0.1ms) CREATE UNIQUE INDEX "index_games_on_player_and_mission" ON "break_escape_games" ("player_type", "player_id", "mission_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_player" ON "break_escape_games" ("player_type", "player_id")  (0.2ms) CREATE INDEX "index_break_escape_games_on_status" ON "break_escape_games" ("status")  (0.1ms) DROP TABLE IF EXISTS "break_escape_missions"  (0.2ms) CREATE TABLE "break_escape_missions" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime(6) NOT NULL, "description" text, "difficulty_level" integer DEFAULT 1 NOT NULL, "display_name" varchar NOT NULL, "name" varchar NOT NULL, "published" boolean DEFAULT FALSE NOT NULL, "updated_at" datetime(6) NOT NULL)  (0.2ms) CREATE UNIQUE INDEX "index_break_escape_missions_on_name" ON "break_escape_missions" ("name")  (0.2ms) 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 immediate TRANSACTION  (0.2ms) CREATE TEMPORARY TABLE "abreak_escape_games" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "completed_at" datetime(6), "created_at" datetime(6) NOT NULL, "mission_id" integer NOT NULL, "player_id" integer NOT NULL, "player_state" json DEFAULT '"{\"currentRoom\":null,\"unlockedRooms\":[],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"' NOT NULL, "player_type" varchar NOT NULL, "scenario_data" json NOT NULL, "score" integer DEFAULT 0 NOT NULL, "started_at" datetime(6), "status" varchar DEFAULT 'in_progress' NOT NULL, "updated_at" datetime(6) NOT NULL)  (0.1ms) CREATE INDEX "tindex_abreak_escape_games_on_status" ON "abreak_escape_games" ("status")  (0.1ms) CREATE INDEX "tindex_abreak_escape_games_on_player" ON "abreak_escape_games" ("player_type", "player_id")  (0.2ms) CREATE UNIQUE INDEX "tindex_games_on_player_and_mission" ON "abreak_escape_games" ("player_type", "player_id", "mission_id")  (0.1ms) CREATE INDEX "tindex_abreak_escape_games_on_mission_id" ON "abreak_escape_games" ("mission_id") SQL (0.2ms) INSERT INTO "abreak_escape_games" ("id","completed_at","created_at","mission_id","player_id","player_state","player_type","scenario_data","score","started_at","status","updated_at") SELECT "id","completed_at","created_at","mission_id","player_id","player_state","player_type","scenario_data","score","started_at","status","updated_at" FROM "break_escape_games"  (0.4ms) DROP TABLE "break_escape_games"  (0.2ms) CREATE TABLE "break_escape_games" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "completed_at" datetime(6), "created_at" datetime(6) NOT NULL, "mission_id" integer NOT NULL, "player_id" integer NOT NULL, "player_state" json DEFAULT '"{\"currentRoom\":null,\"unlockedRooms\":[],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"' NOT NULL, "player_type" varchar NOT NULL, "scenario_data" json NOT NULL, "score" integer DEFAULT 0 NOT NULL, "started_at" datetime(6), "status" varchar DEFAULT 'in_progress' NOT NULL, "updated_at" datetime(6) NOT NULL, CONSTRAINT "fk_rails_ce758a8dd4" FOREIGN KEY ("mission_id") REFERENCES "break_escape_missions" ("id") )  (0.1ms) CREATE INDEX "index_break_escape_games_on_mission_id" ON "break_escape_games" ("mission_id")  (0.1ms) CREATE UNIQUE INDEX "index_games_on_player_and_mission" ON "break_escape_games" ("player_type", "player_id", "mission_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_player" ON "break_escape_games" ("player_type", "player_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_status" ON "break_escape_games" ("status") SQL (0.7ms) INSERT INTO "break_escape_games" ("id","completed_at","created_at","mission_id","player_id","player_state","player_type","scenario_data","score","started_at","status","updated_at") SELECT "id","completed_at","created_at","mission_id","player_id","player_state","player_type","scenario_data","score","started_at","status","updated_at" FROM "abreak_escape_games"  (0.2ms) DROP TABLE "abreak_escape_games" TRANSACTION (0.1ms) COMMIT TRANSACTION  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1  (0.2ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL PRIMARY KEY) ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC  (0.2ms) INSERT INTO "schema_migrations" (version) VALUES (20251120160000)  (0.3ms) INSERT INTO "schema_migrations" (version) VALUES (20251120155358), (20251120155357);  (0.3ms) 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.1ms) 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.2ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ('environment', 'test', '2025-11-20 17:23:21.162347', '2025-11-20 17:23:21.162351') RETURNING "key" 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, "environment"]] 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::InternalMetadata Create (0.1ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ('schema_sha1', '33181f3d58f9bab484a9b348ce1e6b298e81ba9b', '2025-11-20 17:23:21.163822', '2025-11-20 17:23:21.163824') RETURNING "key" ActiveRecord::SchemaMigration Load (0.6ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.4ms) 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.3ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:23:21', 'test_user', 'user', '2025-11-20 17:23:21'), (NULL, '2025-11-20 17:23:21', 'other_user', 'user', '2025-11-20 17:23:21'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:23:21', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:23:21'), (NULL, '2025-11-20 17:23:21', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:23:21')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (3.5ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ---------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-20 17:23:22 +0000 Processing by BreakEscape::MissionsController#index as HTML Completed 500 Internal Server Error in 43ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_show_published_mission ----------------------------------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ------------------------------------------------ BreakEscape::GameTest: test_should_update_health ------------------------------------------------ TRANSACTION (0.1ms) ROLLBACK TRANSACTION Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.3ms) 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", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:24:03', 'test_user', 'user', '2025-11-20 17:24:03'), (NULL, '2025-11-20 17:24:03', 'other_user', 'user', '2025-11-20 17:24:03'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:24:03', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:24:03'), (NULL, '2025-11-20 17:24:03', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:24:03')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (5.3ms) COMMIT TRANSACTION  (0.2ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_presence_of_name --------------------------------------------------------------- BreakEscape::Mission Exists? (0.2ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_uniqueness_of_name ----------------------------------------------------------------- TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Exists? (0.3ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] BreakEscape::Mission Create (0.2ms) INSERT INTO "break_escape_missions" ("created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["created_at", "2025-11-20 17:24:03.653615"], ["description", nil], ["difficulty_level", 1], ["display_name", "Test"], ["name", "test"], ["published", 0], ["updated_at", "2025-11-20 17:24:03.653615"]] TRANSACTION (0.1ms) RELEASE 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]] TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.0ms) BEGIN deferred TRANSACTION ------------------------------------------------------------------------------ BreakEscape::MissionTest: test_published_scope_returns_only_published_missions ------------------------------------------------------------------------------ TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::MissionTest: test_scenario_path_returns_correct_path ----------------------------------------------------------------- TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ---------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-20 17:24:04 +0000 Processing by BreakEscape::MissionsController#index as HTML 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]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.4ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 2.9ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 3.8ms | GC: 0.0ms) Completed 200 OK in 62ms (Views: 19.1ms | ActiveRecord: 0.9ms (2 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_show_published_mission ----------------------------------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------- BreakEscapeTest: test_it_has_a_version_number --------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION -------------------------------------------------- BreakEscape::GameTest: test_should_track_inventory -------------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ---------------------------------------------- BreakEscape::GameTest: test_should_unlock_room ---------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ------------------------------------------------ BreakEscape::GameTest: test_should_update_health ------------------------------------------------ TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------------------------- BreakEscape::GameTest: test_should_belong_to_player_and_mission --------------------------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 ----------------------------------------------------------------- TRANSACTION (0.0ms) ROLLBACK TRANSACTION Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.5ms) PRAGMA foreign_keys  (0.1ms) 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", "created_at", "handle", "role", "updated_at") VALUES (NULL, '2025-11-20 17:24:29', 'test_user', 'user', '2025-11-20 17:24:29'), (NULL, '2025-11-20 17:24:29', 'other_user', 'user', '2025-11-20 17:24:29'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (NULL, '2025-11-20 17:24:29', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:24:29'), (NULL, '2025-11-20 17:24:29', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:24:29')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.6ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.0ms) BEGIN deferred TRANSACTION --------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_presence_of_name --------------------------------------------------------------- BreakEscape::Mission Exists? (0.2ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_uniqueness_of_name ----------------------------------------------------------------- TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Exists? (0.3ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] BreakEscape::Mission Create (0.3ms) INSERT INTO "break_escape_missions" ("created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["created_at", "2025-11-20 17:24:30.005081"], ["description", nil], ["difficulty_level", 1], ["display_name", "Test"], ["name", "test"], ["published", 0], ["updated_at", "2025-11-20 17:24:30.005081"]] TRANSACTION (0.1ms) RELEASE 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]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::MissionTest: test_scenario_path_returns_correct_path ----------------------------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ------------------------------------------------------------------------------ BreakEscape::MissionTest: test_published_scope_returns_only_published_missions ------------------------------------------------------------------------------ TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------- BreakEscapeTest: test_it_has_a_version_number --------------------------------------------- TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_show_published_mission ----------------------------------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.4ms) BEGIN deferred TRANSACTION ---------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-20 17:24:30 +0000 Processing by BreakEscape::MissionsController#index as HTML BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 2.2ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 3.2ms | GC: 0.0ms) Completed 200 OK in 57ms (Views: 17.5ms | ActiveRecord: 0.7ms (2 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ---------------------------------------------- BreakEscape::GameTest: test_should_unlock_room ---------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.0ms) BEGIN deferred TRANSACTION ------------------------------------------------ BreakEscape::GameTest: test_should_update_health ------------------------------------------------ TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION -------------------------------------------------- BreakEscape::GameTest: test_should_track_inventory -------------------------------------------------- TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 ----------------------------------------------------------------- TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------------------------- BreakEscape::GameTest: test_should_belong_to_player_and_mission --------------------------------------------------------------- TRANSACTION (0.0ms) ROLLBACK TRANSACTION Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::InternalMetadata Load (0.6ms) 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.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.4ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (149617800, '2025-11-20 17:25:07', 'test_user', 'user', '2025-11-20 17:25:07'), (618102942, '2025-11-20 17:25:07', 'other_user', 'user', '2025-11-20 17:25:07'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (418560898, '2025-11-20 17:25:07', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:25:07'), (636030761, '2025-11-20 17:25:07', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:25:07')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (54.5ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::MissionTest: test_scenario_path_returns_correct_path ----------------------------------------------------------------- BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ------------------------------------------------------------------------------ BreakEscape::MissionTest: test_published_scope_returns_only_published_missions ------------------------------------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Mission Exists? (0.1ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 636030761], ["LIMIT", 1]] BreakEscape::Mission Exists? (0.1ms) 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.1ms) BEGIN deferred TRANSACTION --------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_presence_of_name --------------------------------------------------------------- BreakEscape::Mission Exists? (0.1ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_uniqueness_of_name ----------------------------------------------------------------- TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Exists? (0.3ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] BreakEscape::Mission Create (0.2ms) INSERT INTO "break_escape_missions" ("created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["created_at", "2025-11-20 17:25:07.298681"], ["description", nil], ["difficulty_level", 1], ["display_name", "Test"], ["name", "test"], ["published", 0], ["updated_at", "2025-11-20 17:25:07.298681"]] TRANSACTION (0.0ms) RELEASE 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]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ---------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-20 17:25:07 +0000 Processing by BreakEscape::MissionsController#index as HTML BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 2.4ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 3.3ms | GC: 0.0ms) Completed 200 OK in 56ms (Views: 17.6ms | ActiveRecord: 0.5ms (2 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_show_published_mission ----------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) 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-20 17:25:07 +0000 Processing by BreakEscape::MissionsController#show as HTML Parameters: {"id"=>"418560898"} 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" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::Game Load (0.2ms) 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.1ms) SAVEPOINT active_record_1 TRANSACTION (0.1ms) ROLLBACK TO SAVEPOINT active_record_1 Completed 500 Internal Server Error in 56ms (ActiveRecord: 1.0ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 ----------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.0ms) BEGIN deferred TRANSACTION ------------------------------------------------ BreakEscape::GameTest: test_should_update_health ------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------------------------- BreakEscape::GameTest: test_should_belong_to_player_and_mission --------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION -------------------------------------------------- BreakEscape::GameTest: test_should_track_inventory -------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred 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.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------- BreakEscapeTest: test_it_has_a_version_number --------------------------------------------- TRANSACTION (0.0ms) ROLLBACK TRANSACTION Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.7ms) PRAGMA foreign_keys  (0.1ms) PRAGMA defer_foreign_keys  (0.1ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (149617800, '2025-11-20 17:59:19', 'test_user', 'user', '2025-11-20 17:59:19'), (618102942, '2025-11-20 17:59:19', 'other_user', 'user', '2025-11-20 17:59:19'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (418560898, '2025-11-20 17:59:19', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 17:59:19'), (636030761, '2025-11-20 17:59:19', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 17:59:19')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (5.5ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.0ms) BEGIN deferred TRANSACTION ------------------------------------------------ BreakEscape::GameTest: test_should_update_health ------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------------------------- BreakEscape::GameTest: test_should_belong_to_player_and_mission --------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 ----------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred 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.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION -------------------------------------------------- BreakEscape::GameTest: test_should_track_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.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_show_published_mission ----------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) 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-20 17:59:19 +0000 Processing by BreakEscape::MissionsController#show as HTML Parameters: {"id"=>"418560898"} BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) 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.2ms) 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]] Completed 500 Internal Server Error in 15ms (ActiveRecord: 0.5ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ---------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-20 17:59:20 +0000 Processing by BreakEscape::MissionsController#index as HTML 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]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 2.2ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 3.1ms | GC: 0.0ms) Completed 200 OK in 53ms (Views: 19.4ms | ActiveRecord: 0.3ms (2 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_uniqueness_of_name ----------------------------------------------------------------- TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Exists? (0.4ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] BreakEscape::Mission Create (0.3ms) INSERT INTO "break_escape_missions" ("created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["created_at", "2025-11-20 17:59:20.159340"], ["description", nil], ["difficulty_level", 1], ["display_name", "Test"], ["name", "test"], ["published", 0], ["updated_at", "2025-11-20 17:59:20.159340"]] TRANSACTION (0.1ms) RELEASE 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]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ------------------------------------------------------------------------------ BreakEscape::MissionTest: test_published_scope_returns_only_published_missions ------------------------------------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Mission Exists? (0.1ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 636030761], ["LIMIT", 1]] BreakEscape::Mission Exists? (0.1ms) 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.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred 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.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_presence_of_name --------------------------------------------------------------- BreakEscape::Mission Exists? (0.2ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------- BreakEscapeTest: test_it_has_a_version_number --------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::InternalMetadata Load (0.6ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.5ms) PRAGMA foreign_keys  (0.1ms) PRAGMA defer_foreign_keys  (0.1ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "created_at", "handle", "role", "updated_at") VALUES (149617800, '2025-11-20 18:00:25', 'test_user', 'user', '2025-11-20 18:00:25'), (618102942, '2025-11-20 18:00:25', 'other_user', 'user', '2025-11-20 18:00:25'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (418560898, '2025-11-20 18:00:25', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 18:00:25'), (636030761, '2025-11-20 18:00:25', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 18:00:25')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (7.3ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------- BreakEscapeTest: test_it_has_a_version_number --------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ---------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-20 18:00:25 +0000 Processing by BreakEscape::MissionsController#index as HTML BreakEscape::DemoUser Load (0.3ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 5.0ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 5.9ms | GC: 0.0ms) Completed 200 OK in 129ms (Views: 33.4ms | ActiveRecord: 0.4ms (2 queries, 0 cached) | GC: 20.0ms) TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.0ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_show_published_mission ----------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) 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-20 18:00:26 +0000 Processing by BreakEscape::MissionsController#show as HTML Parameters: {"id"=>"418560898"} 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" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::Game Load (0.2ms) 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.3ms) INSERT INTO "break_escape_games" ("completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["completed_at", nil], ["created_at", "2025-11-20 18:00:26.131316"], ["mission_id", 418560898], ["player_id", 149617800], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["player_type", "BreakEscape::DemoUser"], ["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\",\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName && data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName && 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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["score", 0], ["started_at", "2025-11-20 18:00:26.136014"], ["status", "in_progress"], ["updated_at", "2025-11-20 18:00:26.131316"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 71ms (ActiveRecord: 1.2ms (4 queries, 0 cached) | GC: 10.0ms) TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_presence_of_name --------------------------------------------------------------- BreakEscape::Mission Exists? (0.2ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred 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.1ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 636030761], ["LIMIT", 1]] BreakEscape::Mission Exists? (0.1ms) 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.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_uniqueness_of_name ----------------------------------------------------------------- TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Exists? (0.3ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] BreakEscape::Mission Create (1.5ms) INSERT INTO "break_escape_missions" ("created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["created_at", "2025-11-20 18:00:26.168627"], ["description", nil], ["difficulty_level", 1], ["display_name", "Test"], ["name", "test"], ["published", 0], ["updated_at", "2025-11-20 18:00:26.168627"]] TRANSACTION (0.1ms) RELEASE 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]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred 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.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred 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 (1.6ms) 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 (1.8ms) INSERT INTO "break_escape_games" ("completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["completed_at", nil], ["created_at", "2025-11-20 18:00:26.185151"], ["mission_id", 418560898], ["player_id", 149617800], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["player_type", "BreakEscape::DemoUser"], ["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\",\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName && data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName && 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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["score", 0], ["started_at", "2025-11-20 18:00:26.190791"], ["status", "in_progress"], ["updated_at", "2025-11-20 18:00:26.185151"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (1.6ms) 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-20 18:00:26.198136"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------------------------- BreakEscape::GameTest: test_should_belong_to_player_and_mission --------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["completed_at", nil], ["created_at", "2025-11-20 18:00:26.202787"], ["mission_id", 418560898], ["player_id", 149617800], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["player_type", "BreakEscape::DemoUser"], ["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\",\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName && data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName && 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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["score", 0], ["started_at", "2025-11-20 18:00:26.204368"], ["status", "in_progress"], ["updated_at", "2025-11-20 18:00:26.202787"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.0ms) BEGIN deferred TRANSACTION -------------------------------------------------- BreakEscape::GameTest: test_should_track_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.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["completed_at", nil], ["created_at", "2025-11-20 18:00:26.208849"], ["mission_id", 418560898], ["player_id", 149617800], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["player_type", "BreakEscape::DemoUser"], ["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\",\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName && data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName && 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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["score", 0], ["started_at", "2025-11-20 18:00:26.210401"], ["status", "in_progress"], ["updated_at", "2025-11-20 18:00:26.208849"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"key\",\"name\":\"Test Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-20 18:00:26.212813"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ------------------------------------------------ BreakEscape::GameTest: test_should_update_health ------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["completed_at", nil], ["created_at", "2025-11-20 18:00:26.215875"], ["mission_id", 418560898], ["player_id", 149617800], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["player_type", "BreakEscape::DemoUser"], ["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\",\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName && data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName && 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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["score", 0], ["started_at", "2025-11-20 18:00:26.217706"], ["status", "in_progress"], ["updated_at", "2025-11-20 18:00:26.215875"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":50}"], ["updated_at", "2025-11-20 18:00:26.219691"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 ----------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["completed_at", nil], ["created_at", "2025-11-20 18:00:26.222335"], ["mission_id", 418560898], ["player_id", 149617800], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["player_type", "BreakEscape::DemoUser"], ["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\",\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName && data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName && 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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["score", 0], ["started_at", "2025-11-20 18:00:26.223912"], ["status", "in_progress"], ["updated_at", "2025-11-20 18:00:26.222335"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":0}"], ["updated_at", "2025-11-20 18:00:26.227047"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) ROLLBACK TRANSACTION Generating image variants require the image_processing gem. Please add `gem "image_processing", "~> 1.2"` to your Gemfile or set `config.active_storage.variant_processor = :disabled`. ActiveRecord::InternalMetadata Load (0.6ms) 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.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) BEGIN immediate TRANSACTION  (0.5ms) 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", "created_at", "handle", "role", "updated_at") VALUES (149617800, '2025-11-20 18:01:17', 'test_user', 'user', '2025-11-20 18:01:17'), (618102942, '2025-11-20 18:01:17', 'other_user', 'user', '2025-11-20 18:01:17'); INSERT INTO "break_escape_missions" ("id", "created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (418560898, '2025-11-20 18:01:17', 'Test scenario', 3, 'CEO Exfiltration', 'ceo_exfil', TRUE, '2025-11-20 18:01:17'), (636030761, '2025-11-20 18:01:17', 'Not visible', 1, 'Unpublished Test', 'test_unpublished', FALSE, '2025-11-20 18:01:17')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.7ms) COMMIT TRANSACTION  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.0ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_show_published_mission ----------------------------------------------------------------------- BreakEscape::Mission Load (0.4ms) 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-20 18:01:17 +0000 Processing by BreakEscape::MissionsController#show as HTML Parameters: {"id"=>"418560898"} BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.5ms) 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.2ms) 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.4ms) INSERT INTO "break_escape_games" ("completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["completed_at", nil], ["created_at", "2025-11-20 18:01:17.484917"], ["mission_id", 418560898], ["player_id", 149617800], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["player_type", "BreakEscape::DemoUser"], ["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\",\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName && data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName && 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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["score", 0], ["started_at", "2025-11-20 18:01:17.486680"], ["status", "in_progress"], ["updated_at", "2025-11-20 18:01:17.484917"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 84ms (ActiveRecord: 1.8ms (4 queries, 0 cached) | GC: 10.0ms) TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ---------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-20 18:01:17 +0000 Processing by BreakEscape::MissionsController#index as HTML BreakEscape::DemoUser Load (0.3ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 3.7ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 8.1ms | GC: 0.0ms) Completed 200 OK in 69ms (Views: 29.8ms | ActiveRecord: 0.5ms (2 queries, 0 cached) | GC: 10.0ms) TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------- BreakEscapeTest: test_it_has_a_version_number --------------------------------------------- TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::MissionTest: test_scenario_path_returns_correct_path ----------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_uniqueness_of_name ----------------------------------------------------------------- TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Exists? (1.9ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] BreakEscape::Mission Create (0.2ms) INSERT INTO "break_escape_missions" ("created_at", "description", "difficulty_level", "display_name", "name", "published", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["created_at", "2025-11-20 18:01:17.608201"], ["description", nil], ["difficulty_level", 1], ["display_name", "Test"], ["name", "test"], ["published", 0], ["updated_at", "2025-11-20 18:01:17.608201"]] TRANSACTION (0.1ms) RELEASE 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]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_presence_of_name --------------------------------------------------------------- BreakEscape::Mission Exists? (0.1ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ------------------------------------------------------------------------------ BreakEscape::MissionTest: test_published_scope_returns_only_published_missions ------------------------------------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Mission Exists? (1.8ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 636030761], ["LIMIT", 1]] BreakEscape::Mission Exists? (0.1ms) 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 (1.8ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ----------------------------------------------------------------- BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 ----------------------------------------------------------------- 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 (1.6ms) 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 (1.5ms) INSERT INTO "break_escape_games" ("completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["completed_at", nil], ["created_at", "2025-11-20 18:01:17.639709"], ["mission_id", 418560898], ["player_id", 149617800], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["player_type", "BreakEscape::DemoUser"], ["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\",\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName && data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName && 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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["score", 0], ["started_at", "2025-11-20 18:01:17.646073"], ["status", "in_progress"], ["updated_at", "2025-11-20 18:01:17.639709"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":0}"], ["updated_at", "2025-11-20 18:01:17.655056"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.0ms) BEGIN deferred 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.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["completed_at", nil], ["created_at", "2025-11-20 18:01:17.658509"], ["mission_id", 418560898], ["player_id", 149617800], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["player_type", "BreakEscape::DemoUser"], ["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\",\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName && data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName && 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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["score", 0], ["started_at", "2025-11-20 18:01:17.660309"], ["status", "in_progress"], ["updated_at", "2025-11-20 18:01:17.658509"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-20 18:01:17.663594"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION ------------------------------------------------ BreakEscape::GameTest: test_should_update_health ------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["completed_at", nil], ["created_at", "2025-11-20 18:01:17.666885"], ["mission_id", 418560898], ["player_id", 149617800], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["player_type", "BreakEscape::DemoUser"], ["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\",\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName && data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName && 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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["score", 0], ["started_at", "2025-11-20 18:01:17.668395"], ["status", "in_progress"], ["updated_at", "2025-11-20 18:01:17.666885"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":50}"], ["updated_at", "2025-11-20 18:01:17.670874"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.0ms) BEGIN deferred TRANSACTION -------------------------------------------------- BreakEscape::GameTest: test_should_track_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.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["completed_at", nil], ["created_at", "2025-11-20 18:01:17.673624"], ["mission_id", 418560898], ["player_id", 149617800], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["player_type", "BreakEscape::DemoUser"], ["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\",\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName && data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName && 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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["score", 0], ["started_at", "2025-11-20 18:01:17.675209"], ["status", "in_progress"], ["updated_at", "2025-11-20 18:01:17.673624"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"key\",\"name\":\"Test Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-20 18:01:17.678012"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) ROLLBACK TRANSACTION TRANSACTION (0.1ms) BEGIN deferred TRANSACTION --------------------------------------------------------------- BreakEscape::GameTest: test_should_belong_to_player_and_mission --------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("completed_at", "created_at", "mission_id", "player_id", "player_state", "player_type", "scenario_data", "score", "started_at", "status", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["completed_at", nil], ["created_at", "2025-11-20 18:01:17.681208"], ["mission_id", 418560898], ["player_id", 149617800], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["player_type", "BreakEscape::DemoUser"], ["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\",\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName && data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName && 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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["score", 0], ["started_at", "2025-11-20 18:01:17.682545"], ["status", "in_progress"], ["updated_at", "2025-11-20 18:01:17.681208"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) ROLLBACK TRANSACTION  (1.2ms) DROP TABLE IF EXISTS "break_escape_demo_users"  (3.7ms) 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.2ms) CREATE UNIQUE INDEX "index_break_escape_demo_users_on_handle" ON "break_escape_demo_users" ("handle")  (0.1ms) DROP TABLE IF EXISTS "break_escape_games"  (0.2ms) 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.1ms) CREATE INDEX "index_break_escape_games_on_mission_id" ON "break_escape_games" ("mission_id")  (0.1ms) CREATE UNIQUE INDEX "index_games_on_player_and_mission" ON "break_escape_games" ("player_type", "player_id", "mission_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_player" ON "break_escape_games" ("player_type", "player_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_status" ON "break_escape_games" ("status")  (0.1ms) DROP TABLE IF EXISTS "break_escape_missions"  (0.2ms) 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)  (0.2ms) CREATE UNIQUE INDEX "index_break_escape_missions_on_name" ON "break_escape_missions" ("name")  (0.2ms) CREATE INDEX "index_break_escape_missions_on_published" ON "break_escape_missions" ("published")  (0.1ms) 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.2ms) 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.1ms) CREATE INDEX "tindex_abreak_escape_games_on_status" ON "abreak_escape_games" ("status")  (0.1ms) CREATE INDEX "tindex_abreak_escape_games_on_player" ON "abreak_escape_games" ("player_type", "player_id")  (0.1ms) CREATE UNIQUE INDEX "tindex_games_on_player_and_mission" ON "abreak_escape_games" ("player_type", "player_id", "mission_id")  (0.1ms) CREATE INDEX "tindex_abreak_escape_games_on_mission_id" ON "abreak_escape_games" ("mission_id")  (0.1ms) 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.4ms) DROP TABLE "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, CONSTRAINT "fk_rails_ce758a8dd4" FOREIGN KEY ("mission_id") REFERENCES "break_escape_missions" ("id") )  (0.1ms) CREATE INDEX "index_break_escape_games_on_mission_id" ON "break_escape_games" ("mission_id")  (0.1ms) CREATE UNIQUE INDEX "index_games_on_player_and_mission" ON "break_escape_games" ("player_type", "player_id", "mission_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_player" ON "break_escape_games" ("player_type", "player_id")  (0.1ms) CREATE INDEX "index_break_escape_games_on_status" ON "break_escape_games" ("status")  (0.1ms) 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.2ms) DROP TABLE "abreak_escape_games" TRANSACTION (0.1ms) commit transaction  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1  (0.2ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL PRIMARY KEY) ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC  (0.2ms) INSERT INTO "schema_migrations" (version) VALUES (20251120160000)  (0.1ms) INSERT INTO "schema_migrations" (version) VALUES (20251120155358), (20251120155357);  (0.2ms) 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.1ms) 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.1ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ('environment', 'test', '2025-11-20 21:05:49.963422', '2025-11-20 21:05:49.963425') RETURNING "key" 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, "environment"]] 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::InternalMetadata Create (0.1ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ('schema_sha1', '3156eb58d4eb7b0307ecdc7a31a49a7fb7dbbf3a', '2025-11-20 21:05:49.964715', '2025-11-20 21:05:49.964717') RETURNING "key" ActiveRecord::SchemaMigration Load (0.4ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.3ms) 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.3ms) 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-20 21:05:50', '2025-11-20 21:05:50'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-20 21:05:50', '2025-11-20 21:05:50'); 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-20 21:05:50', '2025-11-20 21:05:50'); 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-20 21:05:50', '2025-11-20 21:05:50')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (5.1ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction ------------------------------------------------------- BreakEscape::GamesControllerTest: test_should_show_game ------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.096141"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.093902"], ["updated_at", "2025-11-20 21:05:51.093902"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-20 21:05:51 +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.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application Rendered /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 5.1ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 5.9ms | GC: 0.0ms) Completed 200 OK in 71ms (Views: 20.5ms | ActiveRecord: 0.5ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_scenario_endpoint_should_return_JSON --------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.228329"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.226514"], ["updated_at", "2025-11-20 21:05:51.226514"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-20 21:05:51 +0000 Processing by BreakEscape::GamesController#scenario as HTML Parameters: {"id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] Completed 200 OK in 20ms (Views: 17.3ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 10.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_bootstrap_endpoint_should_return_game_state ---------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.259609"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.257780"], ["updated_at", "2025-11-20 21:05:51.257780"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-20 21:05:51 +0000 Processing by BreakEscape::Api::GamesController#bootstrap as HTML Parameters: {"id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] Completed 200 OK in 3ms (Views: 0.7ms | ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_unlock_endpoint_should_validate_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.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.8ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.276476"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.275144"], ["updated_at", "2025-11-20 21:05:51.275144"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-20 21:05:51 +0000 Processing by BreakEscape::Api::GamesController#unlock as HTML Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"1234", "method"=>"keypad", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.317328"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.315704"], ["updated_at", "2025-11-20 21:05:51.315704"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-20 21:05:51 +0000 Processing by BreakEscape::Api::GamesController#sync_state as HTML Parameters: {"player_state"=>{"currentRoom"=>"office", "health"=>"90"}, "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.5ms (4 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_show_should_inject_game_configuration ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.329194"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.327678"], ["updated_at", "2025-11-20 21:05:51.327678"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-20 21:05:51 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application Rendered /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.7ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.0ms) Completed 200 OK in 3ms (Views: 1.3ms | ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_show_should_return_HTML_with_game_container ---------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.341830"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.340492"], ["updated_at", "2025-11-20 21:05:51.340492"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-20 21:05:51 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application Rendered /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.5ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.7ms | GC: 0.0ms) Completed 200 OK in 3ms (Views: 1.0ms | ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) 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.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.355759"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.354429"], ["updated_at", "2025-11-20 21:05:51.354429"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-20 21:05:51 +0000 Processing by BreakEscape::Api::GamesController#inventory as HTML Parameters: {"item"=>{"type"=>"key", "name"=>"Test Key", "id"=>"test_key"}, "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] Completed 400 Bad Request in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_presence_of_name --------------------------------------------------------------- BreakEscape::Mission Exists? (0.1ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) 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.1ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 636030761], ["LIMIT", 1]] BreakEscape::Mission Exists? (0.1ms) 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.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_uniqueness_of_name ----------------------------------------------------------------- TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Exists? (0.3ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] BreakEscape::Mission Create (0.2ms) INSERT INTO "break_escape_missions" ("name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["name", "test"], ["display_name", "Test"], ["description", nil], ["published", 0], ["difficulty_level", 1], ["created_at", "2025-11-20 21:05:51.380949"], ["updated_at", "2025-11-20 21:05:51.380949"]] TRANSACTION (0.1ms) RELEASE 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]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) 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.1ms) rollback transaction TRANSACTION (0.1ms) 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.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.388467"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.387024"], ["updated_at", "2025-11-20 21:05:51.387024"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-20 21:05:51.391068"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------- BreakEscape::GameTest: test_should_track_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.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.396021"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.394714"], ["updated_at", "2025-11-20 21:05:51.394714"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"key\",\"name\":\"Test Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-20 21:05:51.398869"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------- BreakEscape::GameTest: test_should_belong_to_player_and_mission --------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.402967"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.401631"], ["updated_at", "2025-11-20 21:05:51.401631"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------ BreakEscape::GameTest: test_should_update_health ------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.408189"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.406932"], ["updated_at", "2025-11-20 21:05:51.406932"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "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-20 21:05:51.410421"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------- BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 ----------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.414989"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.413644"], ["updated_at", "2025-11-20 21:05:51.413644"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":0}"], ["updated_at", "2025-11-20 21:05:51.417485"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-20 21:05:51 +0000 Processing by BreakEscape::MissionsController#index as HTML 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]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 1.5ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.8ms | GC: 0.0ms) Completed 200 OK in 6ms (Views: 2.7ms | ActiveRecord: 0.3ms (2 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_create_game_and_redirect_when_showing_mission ---------------------------------------------------------------------------------------------- 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 Count (0.1ms) SELECT COUNT(*) FROM "break_escape_games" Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-20 21:05:51 +0000 Processing by BreakEscape::MissionsController#show as HTML Parameters: {"id"=>"418560898"} 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" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::Game Load (0.2ms) 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.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.439331"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.437929"], ["updated_at", "2025-11-20 21:05:51.437929"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 6ms (ActiveRecord: 0.8ms (4 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Count (0.1ms) SELECT COUNT(*) FROM "break_escape_games" TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_index_should_display_published_missions --------------------------------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-20 21:05:51 +0000 Processing by BreakEscape::MissionsController#index as HTML 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]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.6ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.8ms | GC: 0.0ms) Completed 200 OK in 2ms (Views: 1.1ms | ActiveRecord: 0.2ms (2 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.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_show_published_mission ----------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) 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-20 21:05:51 +0000 Processing by BreakEscape::MissionsController#show as HTML Parameters: {"id"=>"418560898"} 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" 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.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-20 21:05:51.456495"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:05:51.455319"], ["updated_at", "2025-11-20 21:05:51.455319"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 6ms (ActiveRecord: 0.8ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) 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-20 21:05:51 +0000 Processing by BreakEscape::MissionsController#index as HTML 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]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.6ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.0ms) Completed 200 OK in 2ms (Views: 1.1ms | ActiveRecord: 0.2ms (2 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------- BreakEscapeTest: test_it_has_a_version_number --------------------------------------------- TRANSACTION (0.0ms) rollback transaction ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.5ms) PRAGMA foreign_keys  (0.1ms) PRAGMA defer_foreign_keys  (0.1ms) PRAGMA defer_foreign_keys = ON  (0.1ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-20 21:07:05', '2025-11-20 21:07:05'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-20 21:07:05', '2025-11-20 21:07:05'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (418560898, 'ceo_exfil', 'CEO Exfiltration', 'Test scenario', 1, 3, '2025-11-20 21:07:05', '2025-11-20 21:07:05'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (636030761, 'test_unpublished', 'Unpublished Test', 'Not visible', 0, 1, '2025-11-20 21:07:05', '2025-11-20 21:07:05')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.6ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_inventory_endpoint_should_add_items -------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:07:05.980244"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:07:05.977930"], ["updated_at", "2025-11-20 21:07:05.977930"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-20 21:07:06 +0000 Processing by BreakEscape::Api::GamesController#inventory as HTML Parameters: {"item"=>{"type"=>"key", "name"=>"Test Key", "id"=>"test_key"}, "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) 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 30ms (Views: 0.3ms | ActiveRecord: 0.4ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.4ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-20 21:08:00', '2025-11-20 21:08:00'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-20 21:08:00', '2025-11-20 21:08:00'); 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-20 21:08:00', '2025-11-20 21:08:00'); 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-20 21:08:00', '2025-11-20 21:08:00')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.2ms) PRAGMA foreign_keys = 1 TRANSACTION (5.3ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------ BreakEscape::MissionTest: test_published_scope_returns_only_published_missions ------------------------------------------------------------------------------ BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Mission Exists? (0.1ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 636030761], ["LIMIT", 1]] BreakEscape::Mission Exists? (0.1ms) 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.1ms) rollback transaction TRANSACTION (0.1ms) 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.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_uniqueness_of_name ----------------------------------------------------------------- TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Exists? (0.3ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] BreakEscape::Mission Create (0.2ms) INSERT INTO "break_escape_missions" ("name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["name", "test"], ["display_name", "Test"], ["description", nil], ["published", 0], ["difficulty_level", 1], ["created_at", "2025-11-20 21:08:00.569522"], ["updated_at", "2025-11-20 21:08:00.569522"]] TRANSACTION (0.1ms) RELEASE 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]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction --------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_presence_of_name --------------------------------------------------------------- BreakEscape::Mission Exists? (0.1ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-20 21:08:00 +0000 Processing by BreakEscape::MissionsController#index as HTML BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 2.4ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 3.4ms | GC: 0.0ms) Completed 200 OK in 43ms (Views: 16.8ms | ActiveRecord: 0.4ms (2 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) 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-20 21:08:00 +0000 Processing by BreakEscape::MissionsController#index as HTML 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]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.7ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.0ms | GC: 0.0ms) Completed 200 OK in 2ms (Views: 1.3ms | ActiveRecord: 0.2ms (2 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_index_should_display_published_missions --------------------------------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-20 21:08:00 +0000 Processing by BreakEscape::MissionsController#index as HTML 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]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.6ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.8ms | GC: 0.0ms) Completed 200 OK in 2ms (Views: 1.0ms | ActiveRecord: 0.2ms (2 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.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_show_published_mission ----------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) 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-20 21:08:00 +0000 Processing by BreakEscape::MissionsController#show as HTML Parameters: {"id"=>"418560898"} 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" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::Game Load (0.2ms) 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.045057"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.042863"], ["updated_at", "2025-11-20 21:08:01.042863"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 70ms (ActiveRecord: 1.2ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_create_game_and_redirect_when_showing_mission ---------------------------------------------------------------------------------------------- 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 Count (0.1ms) SELECT COUNT(*) FROM "break_escape_games" Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-20 21:08:01 +0000 Processing by BreakEscape::MissionsController#show as HTML Parameters: {"id"=>"418560898"} 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" 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.2ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.059389"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.057550"], ["updated_at", "2025-11-20 21:08:01.057550"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 25ms (ActiveRecord: 1.4ms (4 queries, 0 cached) | GC: 20.0ms) BreakEscape::Game Count (0.1ms) SELECT COUNT(*) FROM "break_escape_games" TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------- BreakEscapeTest: test_it_has_a_version_number --------------------------------------------- TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) 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.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.087370"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.084806"], ["updated_at", "2025-11-20 21:08:01.084806"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-20 21:08:01 +0000 Processing by BreakEscape::Api::GamesController#unlock as HTML Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "method"=>"keypad", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] Completed 422 Unprocessable Content in 22ms (Views: 0.2ms | ActiveRecord: 0.4ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_inventory_endpoint_should_add_items -------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.155540"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.153725"], ["updated_at", "2025-11-20 21:08:01.153725"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-20 21:08:01 +0000 Processing by BreakEscape::Api::GamesController#inventory as HTML Parameters: {"action_type"=>"add", "item"=>{"type"=>"key", "name"=>"Test Key", "id"=>"test_key"}, "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.2ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) 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\":\"key\",\"name\":\"Test Key\",\"id\":\"test_key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-20 21:08:01.162396"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 1.0ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ---------------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_bootstrap_endpoint_should_return_game_state ---------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.167829"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.166438"], ["updated_at", "2025-11-20 21:08:01.166438"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-20 21:08:01 +0000 Processing by BreakEscape::Api::GamesController#bootstrap as HTML Parameters: {"id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] Completed 200 OK in 3ms (Views: 0.2ms | ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_show_should_return_HTML_with_game_container ---------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.181783"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.180140"], ["updated_at", "2025-11-20 21:08:01.180140"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-20 21:08:01 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application Rendered /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 4.7ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 5.0ms | GC: 0.0ms) Completed 200 OK in 10ms (Views: 6.4ms | ActiveRecord: 0.4ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_show_should_inject_game_configuration ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.205255"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.203835"], ["updated_at", "2025-11-20 21:08:01.203835"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-20 21:08:01 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application Rendered /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.7ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.0ms) Completed 200 OK in 3ms (Views: 1.2ms | ActiveRecord: 0.4ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------- BreakEscape::GamesControllerTest: test_should_show_game ------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.219033"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.217210"], ["updated_at", "2025-11-20 21:08:01.217210"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-20 21:08:01 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application Rendered /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.5ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.7ms | GC: 0.0ms) Completed 200 OK in 3ms (Views: 1.0ms | ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.233832"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.231468"], ["updated_at", "2025-11-20 21:08:01.231468"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-20 21:08:01 +0000 Processing by BreakEscape::Api::GamesController#sync_state as HTML Parameters: {"currentRoom"=>"office", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"office\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-20 21:08:01.253945"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_scenario_endpoint_should_return_JSON --------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.259623"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.258335"], ["updated_at", "2025-11-20 21:08:01.258335"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-20 21:08:01 +0000 Processing by BreakEscape::GamesController#scenario as HTML Parameters: {"id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] Completed 200 OK in 2ms (Views: 0.4ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) 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.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.8ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.273236"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.271448"], ["updated_at", "2025-11-20 21:08:01.271448"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-20 21:08:01.276184"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------- BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 ----------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.280686"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.279097"], ["updated_at", "2025-11-20 21:08:01.279097"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":0}"], ["updated_at", "2025-11-20 21:08:01.283246"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------- BreakEscape::GameTest: test_should_belong_to_player_and_mission --------------------------------------------------------------- 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.287536"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.286047"], ["updated_at", "2025-11-20 21:08:01.286047"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------ BreakEscape::GameTest: test_should_update_health ------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.293602"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.292310"], ["updated_at", "2025-11-20 21:08:01.292310"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":50}"], ["updated_at", "2025-11-20 21:08:01.295978"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------- BreakEscape::GameTest: test_should_track_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.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:01.299885"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:01.298664"], ["updated_at", "2025-11-20 21:08:01.298664"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "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-20 21:08:01.302005"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) rollback transaction ActiveRecord::InternalMetadata Load (0.4ms) 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.5ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-20 21:08:51', '2025-11-20 21:08:51'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-20 21:08:51', '2025-11-20 21:08:51'); 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-20 21:08:51', '2025-11-20 21:08:51'); 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-20 21:08:51', '2025-11-20 21:08:51')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (5.2ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------ BreakEscape::MissionTest: test_published_scope_returns_only_published_missions ------------------------------------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Mission Exists? (0.1ms) 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.1ms) 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.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_uniqueness_of_name ----------------------------------------------------------------- TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Exists? (0.3ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] BreakEscape::Mission Create (0.3ms) INSERT INTO "break_escape_missions" ("name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["name", "test"], ["display_name", "Test"], ["description", nil], ["published", 0], ["difficulty_level", 1], ["created_at", "2025-11-20 21:08:51.593879"], ["updated_at", "2025-11-20 21:08:51.593879"]] TRANSACTION (0.1ms) RELEASE 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]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------- BreakEscape::MissionTest: test_should_validate_presence_of_name --------------------------------------------------------------- BreakEscape::Mission Exists? (0.1ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction 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.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_show_published_mission ----------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) 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-20 21:08:51 +0000 Processing by BreakEscape::MissionsController#show as HTML Parameters: {"id"=>"418560898"} BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) 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.2ms) 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.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.025710"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.023699"], ["updated_at", "2025-11-20 21:08:52.023699"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 88ms (ActiveRecord: 1.7ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.2ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_index_should_display_published_missions --------------------------------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-20 21:08:52 +0000 Processing by BreakEscape::MissionsController#index as HTML BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 2.7ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 3.5ms | GC: 0.0ms) Completed 200 OK in 36ms (Views: 19.1ms | ActiveRecord: 0.4ms (2 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.1ms) rollback transaction TRANSACTION (0.1ms) 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-20 21:08:52 +0000 Processing by BreakEscape::MissionsController#index as HTML 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]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.6ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.8ms | GC: 0.0ms) Completed 200 OK in 2ms (Views: 1.1ms | ActiveRecord: 0.2ms (2 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-20 21:08:52 +0000 Processing by BreakEscape::MissionsController#index as HTML BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/user/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.7ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.0ms | GC: 0.0ms) Completed 200 OK in 16ms (Views: 1.2ms | ActiveRecord: 0.2ms (2 queries, 0 cached) | GC: 10.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_create_game_and_redirect_when_showing_mission ---------------------------------------------------------------------------------------------- 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 Count (0.1ms) SELECT COUNT(*) FROM "break_escape_games" Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-20 21:08:52 +0000 Processing by BreakEscape::MissionsController#show as HTML Parameters: {"id"=>"418560898"} 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" 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.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.130948"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.128459"], ["updated_at", "2025-11-20 21:08:52.128459"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 7ms (ActiveRecord: 0.9ms (4 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Count (0.1ms) SELECT COUNT(*) FROM "break_escape_games" TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------- BreakEscapeTest: test_it_has_a_version_number --------------------------------------------- TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_show_should_inject_game_configuration ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.139665"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.138181"], ["updated_at", "2025-11-20 21:08:52.138181"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-20 21:08:52 +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.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application Rendered /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 4.7ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 5.0ms | GC: 0.0ms) Completed 200 OK in 30ms (Views: 6.3ms | ActiveRecord: 0.4ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.184519"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.182794"], ["updated_at", "2025-11-20 21:08:52.182794"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-20 21:08:52 +0000 Processing by BreakEscape::Api::GamesController#sync_state as HTML Parameters: {"currentRoom"=>"office", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"office\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-20 21:08:52.229570"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------- BreakEscape::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.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.235946"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.234150"], ["updated_at", "2025-11-20 21:08:52.234150"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-20 21:08:52 +0000 Processing by BreakEscape::Api::GamesController#unlock as HTML Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "method"=>"keypad", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_bootstrap_endpoint_should_return_game_state ---------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.246947"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.245075"], ["updated_at", "2025-11-20 21:08:52.245075"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-20 21:08:52 +0000 Processing by BreakEscape::Api::GamesController#bootstrap as HTML Parameters: {"id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] Completed 200 OK in 3ms (Views: 0.2ms | ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) 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.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.259934"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.258532"], ["updated_at", "2025-11-20 21:08:52.258532"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-20 21:08:52 +0000 Processing by BreakEscape::Api::GamesController#inventory as HTML Parameters: {"action_type"=>"add", "item"=>{"type"=>"key", "name"=>"Test Key", "id"=>"test_key"}, "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"key\",\"name\":\"Test Key\",\"id\":\"test_key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-20 21:08:52.265424"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------- BreakEscape::GamesControllerTest: test_should_show_game ------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.270844"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.269174"], ["updated_at", "2025-11-20 21:08:52.269174"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-20 21:08:52 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application Rendered /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 13.0ms | GC: 10.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 13.2ms | GC: 10.0ms) Completed 200 OK in 16ms (Views: 13.6ms | ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 10.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_scenario_endpoint_should_return_JSON --------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.8ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.299409"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.297861"], ["updated_at", "2025-11-20 21:08:52.297861"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-20 21:08:52 +0000 Processing by BreakEscape::GamesController#scenario as HTML Parameters: {"id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] Completed 200 OK in 2ms (Views: 0.5ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_show_should_return_HTML_with_game_container ---------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.314028"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.312051"], ["updated_at", "2025-11-20 21:08:52.312051"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-20 21:08:52 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] Rendering layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb Rendering /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application Rendered /home/user/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.6ms | GC: 0.0ms) Rendered layout /home/user/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.8ms | GC: 0.0ms) Completed 200 OK in 5ms (Views: 1.2ms | ActiveRecord: 0.4ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------ BreakEscape::GameTest: test_should_update_health ------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.330671"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.329080"], ["updated_at", "2025-11-20 21:08:52.329080"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":50}"], ["updated_at", "2025-11-20 21:08:52.333028"], ["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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.337490"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.335722"], ["updated_at", "2025-11-20 21:08:52.335722"]] TRANSACTION (0.1ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.343723"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.342247"], ["updated_at", "2025-11-20 21:08:52.342247"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "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-20 21:08:52.346191"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.1ms) 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.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.349974"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.348708"], ["updated_at", "2025-11-20 21:08:52.348708"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-20 21:08:52.352431"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------- BreakEscape::GameTest: test_should_track_inventory -------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-20 21:08:52.356785"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-20 21:08:52.355521"], ["updated_at", "2025-11-20 21:08:52.355521"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"key\",\"name\":\"Test Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-20 21:08:52.359144"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.2ms) 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 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-21 10:02:30', '2025-11-21 10:02:30'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 10:02:30', '2025-11-21 10:02:30'); 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-21 10:02:30', '2025-11-21 10:02:30'); 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-21 10:02:30', '2025-11-21 10:02:30')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.7ms) commit transaction  (0.0ms) PRAGMA foreign_key_check 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-21 10:02:30 +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_Phaser:_main_JS_imports_GAME_CONFIG -------------------------------------------------------------------------------- Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:02:30 +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 1ms (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_core_game_module ------------------------------------------------------------------------------ Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-21 10:02:30 +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_audio_with_correct_MIME_type ---------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-21 10:02:30 +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_Cache-Control ---------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:02:30 +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_null_byte_injection ----------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css%00.jpg" for 127.0.0.1 at 2025-11-21 10:02:30 +0000 Processing by BreakEscape::StaticFilesController#serve as JPEG Parameters: {"path"=>"hud.css\u0000.jpg"} Completed 500 Internal Server Error 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-21 10:02:30 +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-21 10:02:30 +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-21 10:02:30 +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_Security:_should_prevent_directory_traversal_in_JS ----------------------------------------------------------------------------------------------- Started GET "/break_escape/js/../../config/secrets.yml" for 127.0.0.1 at 2025-11-21 10:02:30 +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: 0.5ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.1ms) 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-21 10:02:30 +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_PNG_tiles_with_correct_MIME_type -------------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 10:02:30 +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-21 10:02:30 +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_with_inline_disposition -------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:02:30 +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-21 10:02:30 +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_Phaser:_game.js_has_asset_references_without_prefix ------------------------------------------------------------------------------------------------ Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-21 10:02:30 +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_assets --------------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/../../config/database.yml" for 127.0.0.1 at 2025-11-21 10:02:30 +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-21 10:02:30 +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-21 10:02:30 +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-21 10:02:30 +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-21 10:02:30 +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_Integrity:_audio_files_are_non-empty --------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-21 10:02:30 +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-21 10:02:30 +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:_JavaScript_files_are_non-empty -------------------------------------------------------------------------------------- Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:02:30 +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-21 10:02:30 +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_files_with_correct_MIME_type ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:02:30 +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_return_404_for_non-existent_files ------------------------------------------------------------------------------------------ Started GET "/break_escape/css/non-existent.css" for 127.0.0.1 at 2025-11-21 10:02:30 +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:_CSS_files_are_non-empty ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:02:30 +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-21 10:02:30 +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_return_404_for_non-existent_files --------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/non-existent.mp3" for 127.0.0.1 at 2025-11-21 10:02:30 +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_Routes:_should_capture_complex_paths_with_segments ----------------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:02:30 +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-21 10:02:30 +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-21 10:02:30 +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-21 10:02:30 +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 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-21 10:02:35', '2025-11-21 10:02:35'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 10:02:35', '2025-11-21 10:02:35'); 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-21 10:02:35', '2025-11-21 10:02:35'); 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-21 10:02:35', '2025-11-21 10:02:35')  (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::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-21 10:02:35 +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 2ms (Views: 1.2ms | 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-21 10:02:35 +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_JS:_should_serve_core_game_module ------------------------------------------------------------------------------ Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-21 10:02:35 +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 (3.7ms) Completed 200 OK in 4ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 2.7ms) 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-21 10:02:35 +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-21 10:02:35 +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_return_404_for_non-existent_files ------------------------------------------------------------------------------------------- Started GET "/break_escape/non-existent.html" for 127.0.0.1 at 2025-11-21 10:02:35 +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_Content-Length ----------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:02:35 +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-21 10:02:35 +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::StaticFilesControllerTest: test_Assets:_should_serve_nested_files ------------------------------------------------------------------------------ Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 10:02:35 +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:_image_files_are_non-empty --------------------------------------------------------------------------------- Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 10:02:35 +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_HTML:_should_serve_test_files_with_correct_MIME_type ------------------------------------------------------------------------------------------------- Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 10:02:35 +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-21 10:02:35 +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-21 10:02:35 +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-21 10:02:35 +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:_CSS_files_are_non-empty ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:02:35 +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-21 10:02:35 +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_Security:_should_prevent_directory_traversal_in_CSS ------------------------------------------------------------------------------------------------ Started GET "/break_escape/css/../../config/database.yml" for 127.0.0.1 at 2025-11-21 10:02:35 +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_JS:_should_serve_nested_files -------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:02:35 +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_Phaser:_constants_define_GAME_CONFIG_with_baseURL ---------------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:02:35 +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-21 10:02:35 +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_Minigame:_should_serve_lockpicking_script -------------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 10:02:35 +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-21 10:02:35 +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_null_byte_injection ----------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css%00.jpg" for 127.0.0.1 at 2025-11-21 10:02:35 +0000 Processing by BreakEscape::StaticFilesController#serve as JPEG Parameters: {"path"=>"hud.css\u0000.jpg"} Completed 500 Internal Server Error 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-21 10:02:35 +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-21 10:02:35 +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_Minigame:_should_serve_lockpicking_sounds -------------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-21 10:02:35 +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-21 10:02:35 +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-21 10:02:35 +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:_main_JS_imports_GAME_CONFIG -------------------------------------------------------------------------------- Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:02:35 +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_Routes:_should_capture_complex_paths_with_segments ----------------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:02:35 +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_return_404_for_non-existent_files --------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/non-existent.mp3" for 127.0.0.1 at 2025-11-21 10:02:35 +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_Headers:_should_set_Content-Disposition_to_inline ---------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:02:35 +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:_JavaScript_files_are_non-empty -------------------------------------------------------------------------------------- Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:02:35 +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_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-21 10:02:35 +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 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-21 10:06:27', '2025-11-21 10:06:27'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 10:06:27', '2025-11-21 10:06:27'); 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-21 10:06:27', '2025-11-21 10:06:27'); 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-21 10:06:27', '2025-11-21 10:06:27')  (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::StaticFilesControllerTest: test_Headers:_should_set_Content-Disposition_to_inline ---------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:06:27 +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 (1.1ms) 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::StaticFilesControllerTest: test_Integrity:_CSS_files_are_non-empty ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:06:27 +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-21 10:06:27 +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 4ms (Views: 4.0ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 2.7ms) 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-21 10:06:27 +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.2ms) 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-21 10:06:27 +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_HTML:_should_serve_test_files_with_correct_MIME_type ------------------------------------------------------------------------------------------------- Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 10:06:27 +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_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-21 10:06:27 +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_files_with_correct_MIME_type ------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:06:27 +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:_constants_define_GAME_CONFIG_with_baseURL ---------------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:06:27 +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_with_inline_disposition -------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:06:27 +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_capture_complex_paths_with_segments ----------------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:06:27 +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:_main_JS_imports_GAME_CONFIG -------------------------------------------------------------------------------- Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:06:27 +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_return_404_for_non-existent_files ------------------------------------------------------------------------------------------ Started GET "/break_escape/css/non-existent.css" for 127.0.0.1 at 2025-11-21 10:06:27 +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_nested_files ------------------------------------------------------------------------------ Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 10:06:27 +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.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-21 10:06:27 +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-21 10:06:27 +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_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-21 10:06:27 +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_files_with_correct_MIME_type ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:06:27 +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-21 10:06:27 +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-21 10:06:27 +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:_game.js_has_asset_references_without_prefix ------------------------------------------------------------------------------------------------ Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-21 10:06:27 +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-21 10:06:27 +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-21 10:06:27 +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-21 10:06:27 +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_Content-Length ----------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:06:27 +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-21 10:06:27 +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_return_404_for_non-existent_files ------------------------------------------------------------------------------------------- Started GET "/break_escape/non-existent.html" for 127.0.0.1 at 2025-11-21 10:06:27 +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-21 10:06:27 +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_JS:_should_serve_nested_files -------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:06:27 +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-21 10:06:27 +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.1ms) 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-21 10:06:27 +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_core_game_module ------------------------------------------------------------------------------ Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-21 10:06:27 +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_audio_with_correct_MIME_type ---------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-21 10:06:27 +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 ActiveRecord::InternalMetadata Load (0.2ms) 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-21 10:06:50', '2025-11-21 10:06:50'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 10:06:50', '2025-11-21 10:06:50'); 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-21 10:06:50', '2025-11-21 10:06:50'); 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-21 10:06:50', '2025-11-21 10:06:50')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.8ms) commit transaction  (0.1ms) PRAGMA foreign_key_check 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-21 10:06:50 +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 (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_route_constraints_correctly_capture_file_extensions -------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:06:50 +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-21 10:06:50 +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-21 10:06:50 +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-21 10:06:50 +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-21 10:06:50 +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.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-21 10:06:50 +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-21 10:06:50 +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-21 10:06:50 +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-21 10:06:50 +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-21 10:06:50 +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-21 10:06:50 +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-21 10:06:50 +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-21 10:06:50 +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.1ms) Started GET "/break_escape/assets/sounds/lockpick_wrong.mp3" for 127.0.0.1 at 2025-11-21 10:06:50 +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-21 10:06:50 +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_security:_cannot_access_files_outside_break_escape_directory ----------------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/../../config/secrets.yml" for 127.0.0.1 at 2025-11-21 10:06:50 +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.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-21 10:06:50 +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-21 10:06:50 +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-21 10:06:50 +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_should_serve_sound_manager_module -------------------------------------------------------------------------------- Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-21 10:06:50 +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_minigame_starters ----------------------------------------------------------------------------- Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-21 10:06:50 +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-21 10:06:50 +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-21 10:06:50 +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-21 10:06:50 +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_lockpicking_minigame -------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 10:06:50 +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_test_asset_page_loads_correctly ------------------------------------------------------------------------------ Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 10:06:50 +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_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-21 10:06:50 +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_game_core_with_asset_references ------------------------------------------------------------------------------------------- Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-21 10:06:50 +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_load_GAME_CONFIG_with_proper_baseURL ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:06:50 +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-21 10:06:55', '2025-11-21 10:06:55'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 10:06:55', '2025-11-21 10:06:55'); 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-21 10:06:55', '2025-11-21 10:06:55'); 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-21 10:06:55', '2025-11-21 10:06:55')  (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::AssetLoadingIntegrationTest: test_test_asset_page_loads_correctly ------------------------------------------------------------------------------ Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 10:06:55 +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 (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_route_constraints_correctly_capture_file_extensions -------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:06:55 +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-21 10:06:55 +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-21 10:06:55 +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-21 10:06:55 +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_all_response_headers_are_correct ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:06:55 +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-21 10:06:55 +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-21 10:06:55 +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-21 10:06:55 +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 2ms (Views: 2.0ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.3ms) Started GET "/break_escape/js/../../config/database.yml" for 127.0.0.1 at 2025-11-21 10:06:55 +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) Started GET "/break_escape/assets/../../config/secrets.yml" for 127.0.0.1 at 2025-11-21 10:06:55 +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.2ms) TRANSACTION (0.1ms) 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-21 10:06:55 +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.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-21 10:06:55 +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_baseURL_prevents_duplicate_asset_paths ------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:06:55 +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-21 10:06:55 +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-21 10:06:55 +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_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-21 10:06:55 +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_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-21 10:06:55 +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-21 10:06:55 +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-21 10:06:55 +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-21 10:06:55 +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.2ms) Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) Started GET "/break_escape/assets/sounds/lockpick_reset.mp3" for 127.0.0.1 at 2025-11-21 10:06:55 +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-21 10:06:55 +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-21 10:06:55 +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-21 10:06:55 +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-21 10:06:55 +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.2ms) Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.2ms) Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 10:06:55 +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_sound_manager_module -------------------------------------------------------------------------------- Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-21 10:06:55 +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-21 10:06:55 +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_load_GAME_CONFIG_with_proper_baseURL ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:06:55 +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.2ms) 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-21 10:07:05', '2025-11-21 10:07:05'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 10:07:05', '2025-11-21 10:07:05'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (418560898, 'ceo_exfil', 'CEO Exfiltration', 'Test scenario', 1, 3, '2025-11-21 10:07:05', '2025-11-21 10:07:05'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (636030761, 'test_unpublished', 'Unpublished Test', 'Not visible', 0, 1, '2025-11-21 10:07:05', '2025-11-21 10:07:05')  (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::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-21 10:07:05 +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_route_constraints_correctly_capture_file_extensions -------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:05 +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.0ms) Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:07:05 +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-21 10:07:05 +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-21 10:07:05 +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_test_asset_page_loads_correctly ------------------------------------------------------------------------------ Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 10:07:05 +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_CSS_files_should_be_accessible_from_main_game -------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:05 +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-21 10:07:05 +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-21 10:07:05 +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_load_GAME_CONFIG_with_proper_baseURL ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:07:05 +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::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-21 10:07:05 +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_baseURL_prevents_duplicate_asset_paths ------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:07:05 +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-21 10:07:05 +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.1ms) 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-21 10:07:05 +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_all_response_headers_are_correct ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:05 +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-21 10:07:05 +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-21 10:07:05 +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-21 10:07:05 +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-21 10:07:05 +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-21 10:07:05 +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_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-21 10:07:05 +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-21 10:07:05 +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-21 10:07:05 +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-21 10:07:05 +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-21 10:07:05 +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-21 10:07:05 +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-21 10:07:05 +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-21 10:07:05 +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-21 10:07:05 +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-21 10:07:05 +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 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-21 10:07:10', '2025-11-21 10:07:10'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 10:07:10', '2025-11-21 10:07:10'); 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-21 10:07:10', '2025-11-21 10:07:10'); 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-21 10:07:10', '2025-11-21 10:07:10')  (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::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-21 10:07:10 +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 (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::AssetLoadingIntegrationTest: test_route_constraints_correctly_capture_file_extensions -------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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_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-21 10:07:10 +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-21 10:07:10 +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_baseURL_prevents_duplicate_asset_paths ------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:07:10 +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_all_response_headers_are_correct ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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_lockpicking_minigame -------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 10:07:10 +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-21 10:07:10 +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.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-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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_minigame_starters ----------------------------------------------------------------------------- Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-21 10:07:10 +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_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-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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_GAME_CONFIG_with_proper_baseURL ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:07:10 +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_test_asset_page_loads_correctly ------------------------------------------------------------------------------ Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 10:07:10 +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_JS:_should_return_404_for_non-existent_files ----------------------------------------------------------------------------------------- Started GET "/break_escape/js/non-existent.js" for 127.0.0.1 at 2025-11-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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:_CSS_files_are_non-empty ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:10 +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-21 10:07:10 +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_return_404_for_non-existent_files --------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/non-existent.mp3" for 127.0.0.1 at 2025-11-21 10:07:10 +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_JS:_should_serve_nested_files -------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:07:10 +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_serve_test_files_with_correct_MIME_type ------------------------------------------------------------------------------------------------- Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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_JS:_should_serve_core_game_module ------------------------------------------------------------------------------ Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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_Minigame:_should_serve_lockpicking_sounds -------------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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_serve_PNG_tiles_with_correct_MIME_type -------------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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-21 10:07:10 +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_set_Content-Disposition_to_inline ---------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:10 +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-21 10:07:10 +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:_constants_define_GAME_CONFIG_with_baseURL ---------------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:07:10 +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_handle_files_with_multiple_dots ------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/tiles/door_sheet_32.png" for 127.0.0.1 at 2025-11-21 10:07:10 +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_CSS:_should_serve_with_inline_disposition -------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:10 +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-21 10:07:10 +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_JS ----------------------------------------------------------------------------------------------- Started GET "/break_escape/js/../../config/secrets.yml" for 127.0.0.1 at 2025-11-21 10:07:10 +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-21 10:07:10 +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_CSS:_should_return_404_for_non-existent_files ------------------------------------------------------------------------------------------ Started GET "/break_escape/css/non-existent.css" for 127.0.0.1 at 2025-11-21 10:07:10 +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_Minigame:_should_serve_lockpicking_script -------------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 10:07:10 +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.1ms) 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-21 10:07:10 +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_return_404_for_non-existent_files ------------------------------------------------------------------------------------------- Started GET "/break_escape/non-existent.html" for 127.0.0.1 at 2025-11-21 10:07:10 +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_Integrity:_JavaScript_files_are_non-empty -------------------------------------------------------------------------------------- Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:07:10 +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-21 10:07:38', '2025-11-21 10:07:38'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 10:07:38', '2025-11-21 10:07:38'); 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-21 10:07:38', '2025-11-21 10:07:38'); 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-21 10:07:38', '2025-11-21 10:07:38')  (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::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-21 10:07:38 +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.1ms) 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_CSS_files_should_be_accessible_from_main_game -------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:38 +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_baseURL_prevents_duplicate_asset_paths ------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:07:38 +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_test_asset_page_loads_correctly ------------------------------------------------------------------------------ Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 10:07:38 +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-21 10:07:38 +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-21 10:07:38 +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 3ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 2.7ms) 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-21 10:07:38 +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 2ms (Views: 1.4ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.2ms) Started GET "/break_escape/js/../../config/database.yml" for 127.0.0.1 at 2025-11-21 10:07:38 +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-21 10:07:38 +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_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-21 10:07:38 +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.1ms) Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-21 10:07:38 +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-21 10:07:38 +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-21 10:07:38 +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-21 10:07:38 +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-21 10:07:38 +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.1ms) Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-21 10:07:38 +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-21 10:07:38 +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.1ms) Started GET "/break_escape/assets/sounds/lockpick_wrong.mp3" for 127.0.0.1 at 2025-11-21 10:07:38 +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-21 10:07:38 +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_all_response_headers_are_correct ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:38 +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-21 10:07:38 +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-21 10:07:38 +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.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_should_serve_sound_manager_module -------------------------------------------------------------------------------- Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-21 10:07:38 +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_route_constraints_correctly_capture_file_extensions -------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:38 +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-21 10:07:38 +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-21 10:07:38 +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-21 10:07:38 +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-21 10:07:38 +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-21 10:07:38 +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_minigame_starters ----------------------------------------------------------------------------- Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-21 10:07:38 +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::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-21 10:07:38 +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_Integrity:_audio_files_are_non-empty --------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-21 10:07:38 +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-21 10:07:38 +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-21 10:07:38 +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_Security:_should_prevent_directory_traversal_in_CSS ------------------------------------------------------------------------------------------------ Started GET "/break_escape/css/../../config/database.yml" for 127.0.0.1 at 2025-11-21 10:07:38 +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:_game.js_has_asset_references_without_prefix ------------------------------------------------------------------------------------------------ Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-21 10:07:38 +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_return_404_for_non-existent_files --------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/non-existent.mp3" for 127.0.0.1 at 2025-11-21 10:07:38 +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_CSS:_should_return_404_for_non-existent_files ------------------------------------------------------------------------------------------ Started GET "/break_escape/css/non-existent.css" for 127.0.0.1 at 2025-11-21 10:07:38 +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_nested_files ------------------------------------------------------------------------------ Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 10:07:38 +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_PNG_tiles_with_correct_MIME_type -------------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 10:07:38 +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_Minigame:_should_serve_lockpicking_sounds -------------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-21 10:07:38 +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-21 10:07:38 +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-21 10:07:38 +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_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-21 10:07:38 +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_HTML:_should_serve_test_files_with_correct_MIME_type ------------------------------------------------------------------------------------------------- Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 10:07:38 +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_JS:_should_serve_nested_files -------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:07:38 +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-21 10:07:38 +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_Minigame:_should_serve_lockpicking_script -------------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 10:07:38 +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-21 10:07:38 +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-21 10:07:38 +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_serve_files_with_correct_MIME_type ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:07:38 +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-21 10:07:38 +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-21 10:07:38 +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_Routes:_should_capture_full_filename_with_extension ------------------------------------------------------------------------------------------------ Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:38 +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:_constants_define_GAME_CONFIG_with_baseURL ---------------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:07:38 +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_with_inline_disposition -------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:38 +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-21 10:07:38 +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_Cache-Control ---------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:38 +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-21 10:07:38 +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-21 10:07:38 +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_return_404_for_non-existent_files ------------------------------------------------------------------------------------------- Started GET "/break_escape/non-existent.html" for 127.0.0.1 at 2025-11-21 10:07:38 +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_Routes:_should_capture_complex_paths_with_segments ----------------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:07:38 +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_Headers:_should_set_Content-Disposition_to_inline ---------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:07:38 +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 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-21 10:08:07', '2025-11-21 10:08:07'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 10:08:07', '2025-11-21 10:08:07'); 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-21 10:08:07', '2025-11-21 10:08:07'); 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-21 10:08:07', '2025-11-21 10:08:07')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.6ms) commit transaction  (0.0ms) PRAGMA foreign_key_check 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-21 10:08:07 +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 (1.1ms) 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::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-21 10:08:07 +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 5ms (Views: 5.2ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 3.5ms) 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-21 10:08:07 +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_Routes:_should_capture_full_filename_with_extension ------------------------------------------------------------------------------------------------ Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:08:07 +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-21 10:08:07 +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_Security:_should_prevent_directory_traversal_in_JS ----------------------------------------------------------------------------------------------- Started GET "/break_escape/js/../../config/secrets.yml" for 127.0.0.1 at 2025-11-21 10:08:07 +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.1ms) 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-21 10:08:07 +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_Routes:_should_capture_complex_paths_with_segments ----------------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:08:07 +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.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-21 10:08:07 +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-21 10:08:07 +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_CSS ------------------------------------------------------------------------------------------------ Started GET "/break_escape/css/../../config/database.yml" for 127.0.0.1 at 2025-11-21 10:08:07 +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-21 10:08:07 +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_with_inline_disposition -------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:08:07 +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_Content-Length ----------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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_set_Content-Disposition_to_inline ---------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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_assets --------------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/../../config/database.yml" for 127.0.0.1 at 2025-11-21 10:08:07 +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_Integrity:_JavaScript_files_are_non-empty -------------------------------------------------------------------------------------- Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:08:07 +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_Minigame:_should_serve_lockpicking_sounds -------------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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_Minigame:_should_serve_lockpicking_script -------------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 10:08:07 +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_JS:_should_serve_files_with_correct_MIME_type ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:08:07 +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_return_404_for_non-existent_files ------------------------------------------------------------------------------------------ Started GET "/break_escape/css/non-existent.css" for 127.0.0.1 at 2025-11-21 10:08:07 +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:_CSS_files_are_non-empty ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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_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-21 10:08:07 +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_Cache-Control ---------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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_all_response_headers_are_correct ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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_CSS_files_should_be_accessible_from_main_game -------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:08:07 +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_test_asset_page_loads_correctly ------------------------------------------------------------------------------ Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 10:08:07 +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_security:_cannot_access_files_outside_break_escape_directory ----------------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/../../config/secrets.yml" for 127.0.0.1 at 2025-11-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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_minigame_starters ----------------------------------------------------------------------------- Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-21 10:08:07 +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_load_GAME_CONFIG_with_proper_baseURL ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:08:07 +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_route_constraints_correctly_capture_file_extensions -------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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_lockpicking_minigame -------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 10:08:07 +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_sound_manager_module -------------------------------------------------------------------------------- Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-21 10:08:07 +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_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-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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-21 10:08:07 +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_baseURL_prevents_duplicate_asset_paths ------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:08:07 +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-21 10:08:07 +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_game_core_with_asset_references ------------------------------------------------------------------------------------------- Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-21 10:08:07 +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 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-21 10:09:28', '2025-11-21 10:09:28'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 10:09:28', '2025-11-21 10:09: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-21 10:09:28', '2025-11-21 10:09: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-21 10:09:28', '2025-11-21 10:09:28')  (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::StaticFilesControllerTest: test_Headers:_should_include_Cache-Control ---------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:09: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 (1.0ms) 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::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-21 10:09: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_Assets:_should_serve_nested_files ------------------------------------------------------------------------------ Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 10:09: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.1ms) 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-21 10:09: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 1ms (Views: 1.2ms | 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-21 10:09: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_HTML:_should_serve_test_files_with_correct_MIME_type ------------------------------------------------------------------------------------------------- Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 10:09: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_Integrity:_CSS_files_are_non-empty ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:09: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-21 10:09: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-21 10:09: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-21 10:09: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_Integrity:_image_files_are_non-empty --------------------------------------------------------------------------------- Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 10:09: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_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-21 10:09: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_Phaser:_constants_define_GAME_CONFIG_with_baseURL ---------------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:09: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:_main_JS_imports_GAME_CONFIG -------------------------------------------------------------------------------- Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:09:29 +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-21 10:09:29 +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_core_game_module ------------------------------------------------------------------------------ Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-21 10:09:29 +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:_audio_files_are_non-empty --------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-21 10:09:29 +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_PNG_tiles_with_correct_MIME_type -------------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 10:09:29 +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_CSS ------------------------------------------------------------------------------------------------ Started GET "/break_escape/css/../../config/database.yml" for 127.0.0.1 at 2025-11-21 10:09:29 +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_full_filename_with_extension ------------------------------------------------------------------------------------------------ Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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_with_inline_disposition -------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:09:29 +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-21 10:09:29 +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_files_with_correct_MIME_type ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:09:29 +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-21 10:09:29 +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_return_404_for_non-existent_files ------------------------------------------------------------------------------------------- Started GET "/break_escape/non-existent.html" for 127.0.0.1 at 2025-11-21 10:09:29 +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-21 10:09:29 +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_Minigame:_should_serve_lockpicking_script -------------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 10:09:29 +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_capture_complex_paths_with_segments ----------------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:09:29 +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_Integrity:_JavaScript_files_are_non-empty -------------------------------------------------------------------------------------- Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:09:29 +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_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-21 10:09:29 +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::AssetLoadingIntegrationTest: test_route_constraints_correctly_capture_file_extensions -------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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_all_response_headers_are_correct ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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_sound_manager_module -------------------------------------------------------------------------------- Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-21 10:09:29 +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_security:_cannot_access_files_outside_break_escape_directory ----------------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/../../config/secrets.yml" for 127.0.0.1 at 2025-11-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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_baseURL_prevents_duplicate_asset_paths ------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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_should_load_GAME_CONFIG_with_proper_baseURL ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:09:29 +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_test_asset_page_loads_correctly ------------------------------------------------------------------------------ Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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-21 10:09:29 +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::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-21 10:09:29 +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.2ms) 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-21 10:09:29 +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 1ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.8ms) 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-21 10:18:03', '2025-11-21 10:18:03'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 10:18:03', '2025-11-21 10:18:03'); 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-21 10:18:03', '2025-11-21 10:18:03'); 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-21 10:18:03', '2025-11-21 10:18:03')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (1.7ms) commit transaction  (0.1ms) PRAGMA foreign_key_check 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-21 10:18:03 +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 (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::AssetLoadingIntegrationTest: test_should_serve_minigame_starters ----------------------------------------------------------------------------- Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-21 10:18:03 +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_security:_cannot_access_files_outside_break_escape_directory ----------------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/../../config/secrets.yml" for 127.0.0.1 at 2025-11-21 10:18:03 +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.0ms) Started GET "/break_escape/js/../../config/database.yml" for 127.0.0.1 at 2025-11-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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_CSS_files_should_be_accessible_from_main_game -------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:18:03 +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_door_tile_image --------------------------------------------------------------------------- Started GET "/break_escape/assets/tiles/door.png" for 127.0.0.1 at 2025-11-21 10:18:03 +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_sound_manager_module -------------------------------------------------------------------------------- Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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_route_constraints_correctly_capture_file_extensions -------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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-21 10:18:03 +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_lockpicking_minigame -------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 10:18:03 +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 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-21 10:29:17', '2025-11-21 10:29:17'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 10:29:17', '2025-11-21 10:29:17'); 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-21 10:29:17', '2025-11-21 10:29:17'); 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-21 10:29:17', '2025-11-21 10:29:17')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (1.8ms) commit transaction  (0.0ms) PRAGMA foreign_key_check 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-21 10:29:17 +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 (1.0ms) Completed 200 OK in 2ms (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-21 10:29:17 +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-21 10:29:17 +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-21 10:29:17 +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-21 10:29:17 +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_lockpicking_minigame -------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 10:29:17 +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_sound_manager_module -------------------------------------------------------------------------------- Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-21 10:29:17 +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-21 10:29:17 +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_route_constraints_correctly_capture_file_extensions -------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:29:17 +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-21 10:29:17 +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-21 10:29:17 +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-21 10:29:17 +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_game_core_with_asset_references ------------------------------------------------------------------------------------------- Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-21 10:29:17 +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_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-21 10:29:17 +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_minigame_starters ----------------------------------------------------------------------------- Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-21 10:29:17 +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_CSS_files_should_be_accessible_from_main_game -------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:29:17 +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_door_tile_image --------------------------------------------------------------------------- Started GET "/break_escape/assets/tiles/door.png" for 127.0.0.1 at 2025-11-21 10:29:17 +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_load_all_required_game_files_in_correct_order --------------------------------------------------------------------------------------------------- Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 10:29:17 +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_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-21 10:29:17 +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-21 10:29:17 +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-21 10:29:17 +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-21 10:29:17 +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-21 10:29:17 +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-21 10:29:17 +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.1ms) Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-21 10:29:17 +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-21 10:29:17 +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.1ms) 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-21 10:29:17 +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-21 10:29:17 +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-21 10:29:17 +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_security:_cannot_access_files_outside_break_escape_directory ----------------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/../../config/secrets.yml" for 127.0.0.1 at 2025-11-21 10:29:17 +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-21 10:29:17 +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-21 10:29:17 +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 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-21 10:29:23', '2025-11-21 10:29:23'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 10:29:23', '2025-11-21 10:29:23'); 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-21 10:29:23', '2025-11-21 10:29:23'); 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-21 10:29:23', '2025-11-21 10:29:23')  (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::AssetLoadingIntegrationTest: test_should_serve_minigame_starters ----------------------------------------------------------------------------- Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-21 10:29:23 +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 (1.0ms) Completed 200 OK in 2ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.2ms) 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-21 10:29:23 +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_load_GAME_CONFIG_with_proper_baseURL ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 10:29:23 +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::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-21 10:29:23 +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_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-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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_all_response_headers_are_correct ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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.0ms) Started GET "/break_escape/js/../../config/database.yml" for 127.0.0.1 at 2025-11-21 10:29:23 +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-21 10:29:23 +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_sound_manager_module -------------------------------------------------------------------------------- Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-21 10:29:23 +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_CSS_files_should_be_accessible_from_main_game -------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 10:29:23 +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_game_core_with_asset_references ------------------------------------------------------------------------------------------- Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-21 10:29:23 +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-21 10:29:23 +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_lockpicking_minigame -------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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-21 10:29:23 +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_test_asset_page_loads_correctly ------------------------------------------------------------------------------ Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 10:29:23 +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 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-21 10:38:36', '2025-11-21 10:38:36'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 10:38:36', '2025-11-21 10:38:36'); 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-21 10:38:36', '2025-11-21 10:38:36'); 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-21 10:38:36', '2025-11-21 10:38:36')  (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::NPCInkLoadingTest: test_should_load_NPC_ink_story_via_games_controller_ink_action ---------------------------------------------------------------------------------------------- TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction --------------------------------------------------------------------------------------- BreakEscape::NPCInkLoadingTest: test_should_return_bad_request_if_npc_parameter_missing --------------------------------------------------------------------------------------- TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction --------------------------------------------------------------------------- BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_NPC --------------------------------------------------------------------------- TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::NPCInkLoadingTest: test_npc-lazy-loader_should_have_gameId_from_breakEscapeConfig ---------------------------------------------------------------------------------------------- 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-21 11:10:35', '2025-11-21 11:10:35'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:10:35', '2025-11-21 11:10:35'); 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-21 11:10:35', '2025-11-21 11:10:35'); 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-21 11:10:35', '2025-11-21 11:10:35')  (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::NPCInkLoadingTest: test_should_return_404_for_non-existent_game ---------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:35.892625"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:35.891868"], ["updated_at", "2025-11-21 11:10:35.891868"]] 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-21 11:10:35 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-npc", "id"=>"999999"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 999999], ["LIMIT", 1]] Completed 404 Not Found in 2ms (ActiveRecord: 0.1ms (1 query, 0 cached) | GC: 0.1ms) 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:59: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:168: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_404_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:36.048904"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:36.048347"], ["updated_at", "2025-11-21 11:10:36.048347"]] 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-21 11:10:36 +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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 3ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::NPCInkLoadingTest: test_should_load_existing_NPC_ink_story_and_return_compiled_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:36.055027"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:36.054493"], ["updated_at", "2025-11-21 11:10:36.054493"]] 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-21 11:10:36 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:36.058488"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:36.057991"], ["updated_at", "2025-11-21 11:10:36.057991"]] 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-21 11:10:36 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:36.061735"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:36.061220"], ["updated_at", "2025-11-21 11:10:36.061220"]] 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-21 11:10:36 +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 2ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 1.6ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:36.066036"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:36.065442"], ["updated_at", "2025-11-21 11:10:36.065442"]] 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-21 11:10:36 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:36.069742"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:36.069180"], ["updated_at", "2025-11-21 11:10:36.069180"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:10:36 +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.1ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:36.073273"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:36.072665"], ["updated_at", "2025-11-21 11:10:36.072665"]] 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-21 11:10:36 +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.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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:36.075928"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:36.075437"], ["updated_at", "2025-11-21 11:10:36.075437"]] 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-21 11:10:36 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:36.078634"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:36.078082"], ["updated_at", "2025-11-21 11:10:36.078082"]] 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-21 11:10:36 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::NPCInkLoadingTest: test_should_return_404_for_NPC_without_story_file --------------------------------------------------------------------------------- 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.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:36.097453"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:36.096891"], ["updated_at", "2025-11-21 11:10:36.096891"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:10:36 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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] Loading ink for NPC: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:36.102340"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:36.101697"], ["updated_at", "2025-11-21 11:10:36.101697"]] 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-21 11:10:36 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:36.105382"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:36.104752"], ["updated_at", "2025-11-21 11:10:36.104752"]] 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-21 11:10:36 +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_ink_endpoint_should_handle_URL-encoded_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:36.108086"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:36.107601"], ["updated_at", "2025-11-21 11:10:36.107601"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:10:36.109467"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:10:36.109004"], ["updated_at", "2025-11-21 11:10:36.109004"]] 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-21 11:11:39', '2025-11-21 11:11:39'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:11:39', '2025-11-21 11:11: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-21 11:11:39', '2025-11-21 11:11: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-21 11:11:39', '2025-11-21 11:11:39')  (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::NPCInkLoadingTest: test_npc-manager_should_load_stories_via_API_endpoint ------------------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.490099"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.489488"], ["updated_at", "2025-11-21 11:11:39.489488"]] 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-21 11:11: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.9ms) 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_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.500265"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.499653"], ["updated_at", "2025-11-21 11:11:39.499653"]] 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-21 11:11: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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.503869"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.503305"], ["updated_at", "2025-11-21 11:11:39.503305"]] 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-21 11:11:39 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"security_guard", "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: security_guard [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 3ms (Views: 0.1ms | 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.511994"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.511466"], ["updated_at", "2025-11-21 11:11:39.511466"]] 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-21 11:11: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:59: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:168: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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.656230"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.655696"], ["updated_at", "2025-11-21 11:11:39.655696"]] 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-21 11:11: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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.659266"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.658785"], ["updated_at", "2025-11-21 11:11:39.658785"]] 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-21 11:11: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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.662358"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.661899"], ["updated_at", "2025-11-21 11:11:39.661899"]] 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-21 11:11: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.0ms) Completed 200 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.664830"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.664333"], ["updated_at", "2025-11-21 11:11:39.664333"]] 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-21 11:11: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 (0.0ms) Completed 200 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_handle_URL-encoded_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.667603"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.667041"], ["updated_at", "2025-11-21 11:11:39.667041"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.669266"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.668743"], ["updated_at", "2025-11-21 11:11:39.668743"]] TRANSACTION (0.0ms) ROLLBACK TO SAVEPOINT active_record_1 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.671663"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.671163"], ["updated_at", "2025-11-21 11:11:39.671163"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:11:39 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"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]] Completed 400 Bad Request 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::NPCInkLoadingTest: test_should_load_existing_NPC_ink_story_and_return_compiled_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.675078"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.674535"], ["updated_at", "2025-11-21 11:11:39.674535"]] 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-21 11:11: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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.679649"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.678939"], ["updated_at", "2025-11-21 11:11:39.678939"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:11:39 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.683296"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.682747"], ["updated_at", "2025-11-21 11:11:39.682747"]] 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-21 11:11: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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:39.686716"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:39.686182"], ["updated_at", "2025-11-21 11:11:39.686182"]] 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-21 11:11: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.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-21 11:11:44', '2025-11-21 11:11:44'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:11:44', '2025-11-21 11:11:44'); 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-21 11:11:44', '2025-11-21 11:11:44'); 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-21 11:11:44', '2025-11-21 11:11:44')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.6ms) commit transaction  (0.0ms) PRAGMA foreign_key_check 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.079555"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.078877"], ["updated_at", "2025-11-21 11:11:44.078877"]] 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-21 11:11:44 +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 2ms (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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.089800"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.089213"], ["updated_at", "2025-11-21 11:11:44.089213"]] 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-21 11:11:44 +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:59: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:168: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-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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.237157"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.236635"], ["updated_at", "2025-11-21 11:11:44.236635"]] 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-21 11:11:44 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.240114"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.239634"], ["updated_at", "2025-11-21 11:11:44.239634"]] 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-21 11:11:44 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 2ms (Views: 0.1ms | 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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.247953"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.247355"], ["updated_at", "2025-11-21 11:11:44.247355"]] 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-21 11:11:44 +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.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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.251536"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.250917"], ["updated_at", "2025-11-21 11:11:44.250917"]] 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-21 11:11:44 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.254665"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.254069"], ["updated_at", "2025-11-21 11:11:44.254069"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:11:44 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.257920"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.257409"], ["updated_at", "2025-11-21 11:11:44.257409"]] 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-21 11:11:44 +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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_handle_URL-encoded_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.262639"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.261903"], ["updated_at", "2025-11-21 11:11:44.261903"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.264399"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.263656"], ["updated_at", "2025-11-21 11:11:44.263656"]] TRANSACTION (0.0ms) ROLLBACK TO SAVEPOINT active_record_1 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.267190"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.266679"], ["updated_at", "2025-11-21 11:11:44.266679"]] 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-21 11:11:44 +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_load_existing_NPC_ink_story_and_return_compiled_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.270196"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.269702"], ["updated_at", "2025-11-21 11:11:44.269702"]] 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-21 11:11:44 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.274148"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.273632"], ["updated_at", "2025-11-21 11:11:44.273632"]] 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-21 11:11:44 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.277239"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.276634"], ["updated_at", "2025-11-21 11:11:44.276634"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:11:44 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:11:44.280642"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:11:44.280131"], ["updated_at", "2025-11-21 11:11:44.280131"]] 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-21 11:11:44 +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 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-21 11:12:42', '2025-11-21 11:12:42'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:12:42', '2025-11-21 11:12:42'); 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-21 11:12:42', '2025-11-21 11:12:42'); 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-21 11:12:42', '2025-11-21 11:12:42')  (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::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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:12:42.290003"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:12:42.289321"], ["updated_at", "2025-11-21 11:12:42.289321"]] 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-21 11:12:42 +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 (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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:12:42.300207"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:12:42.299642"], ["updated_at", "2025-11-21 11:12:42.299642"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:12:42 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"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]] Completed 400 Bad Request in 2ms (Views: 0.1ms | 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_handle_URL-encoded_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:12:42.306110"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:12:42.305579"], ["updated_at", "2025-11-21 11:12:42.305579"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::NPCInkLoadingTest: test_should_load_existing_NPC_ink_story_and_return_compiled_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:12:42.308620"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:12:42.308099"], ["updated_at", "2025-11-21 11:12:42.308099"]] 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-21 11:12:42 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:12:42.312010"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:12:42.311477"], ["updated_at", "2025-11-21 11:12:42.311477"]] 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-21 11:12:42 +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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:12:42.315138"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:12:42.314524"], ["updated_at", "2025-11-21 11:12:42.314524"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:12:42 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:12:42.318977"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:12:42.318404"], ["updated_at", "2025-11-21 11:12:42.318404"]] 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-21 11:12:42 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:12:42.321765"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:12:42.321232"], ["updated_at", "2025-11-21 11:12:42.321232"]] 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-21 11:12:42 +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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:12:42.324373"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:12:42.323864"], ["updated_at", "2025-11-21 11:12:42.323864"]] 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-21 11:12:42 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:12:42.326930"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:12:42.326396"], ["updated_at", "2025-11-21 11:12:42.326396"]] 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-21 11:12:42 +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_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:12:42.329441"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:12:42.328920"], ["updated_at", "2025-11-21 11:12:42.328920"]] 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-21 11:12:42 +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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:12:42.332395"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:12:42.331857"], ["updated_at", "2025-11-21 11:12:42.331857"]] 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-21 11:12:42 +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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:12:42.336184"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:12:42.335586"], ["updated_at", "2025-11-21 11:12:42.335586"]] 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-21 11:12:42 +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:59: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:170: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.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction --------------------------------------------------------------------------------------------- BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_return_application/json_content_type --------------------------------------------------------------------------------------------- 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\":\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:12:42.498603"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:12:42.498025"], ["updated_at", "2025-11-21 11:12:42.498025"]] 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-21 11:12:42 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 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-21 11:13:02', '2025-11-21 11:13:02'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:13:02', '2025-11-21 11:13:02'); 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-21 11:13:02', '2025-11-21 11:13:02'); 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-21 11:13:02', '2025-11-21 11:13:02')  (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::NPCInkLoadingTest: test_ink_endpoint_should_handle_URL-encoded_NPC_IDs ----------------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:02.894268"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:02.893555"], ["updated_at", "2025-11-21 11:13:02.893555"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::DemoUser Exists? (0.1ms) SELECT 1 AS one FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."handle" = ? LIMIT ? [["handle", "test_user_d353513d"], ["LIMIT", 1]] BreakEscape::DemoUser Create (0.0ms) INSERT INTO "break_escape_demo_users" ("handle", "role", "created_at", "updated_at") VALUES (?, ?, ?, ?) RETURNING "id" [["handle", "test_user_d353513d"], ["role", "user"], ["created_at", "2025-11-21 11:13:02.896044"], ["updated_at", "2025-11-21 11:13:02.896044"]] 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", 618102943], ["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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:02.896983"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:02.896481"], ["updated_at", "2025-11-21 11:13:02.896481"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/2/ink?npc=npc_with_underscore" for 127.0.0.1 at 2025-11-21 11:13:02 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"npc_with_underscore", "id"=>"2"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 618102943], ["LIMIT", 1]] Redirected to http://www.example.com/break_escape/ Completed 302 Found in 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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:02.910021"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:02.909464"], ["updated_at", "2025-11-21 11:13:02.909464"]] 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-21 11:13:02 +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 (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_load_existing_NPC_ink_story_and_return_compiled_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:02.914473"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:02.913911"], ["updated_at", "2025-11-21 11:13:02.913911"]] 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-21 11:13:02 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:02.918500"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:02.917931"], ["updated_at", "2025-11-21 11:13:02.917931"]] 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-21 11:13:02 +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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:02.921519"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:02.920963"], ["updated_at", "2025-11-21 11:13:02.920963"]] 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-21 11:13:02 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:02.924272"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:02.923745"], ["updated_at", "2025-11-21 11:13:02.923745"]] 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-21 11:13:02 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:02.926851"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:02.926337"], ["updated_at", "2025-11-21 11:13:02.926337"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:13:02 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:02.929996"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:02.929454"], ["updated_at", "2025-11-21 11:13:02.929454"]] 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-21 11:13:02 +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:59: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:170: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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:03.072229"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:03.071714"], ["updated_at", "2025-11-21 11:13:03.071714"]] 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-21 11:13:03 +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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:03.075307"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:03.074820"], ["updated_at", "2025-11-21 11:13:03.074820"]] 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-21 11:13:03 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:03.077975"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:03.077494"], ["updated_at", "2025-11-21 11:13:03.077494"]] 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-21 11:13:03 +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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:03.081175"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:03.080650"], ["updated_at", "2025-11-21 11:13:03.080650"]] 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-21 11:13:03 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:03.085205"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:03.084649"], ["updated_at", "2025-11-21 11:13:03.084649"]] 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-21 11:13:03 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:03.088097"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:03.087542"], ["updated_at", "2025-11-21 11:13:03.087542"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:13:03 +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 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-21 11:13:25', '2025-11-21 11:13:25'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:13:25', '2025-11-21 11:13:25'); 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-21 11:13:25', '2025-11-21 11:13:25'); 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-21 11:13:25', '2025-11-21 11:13:25')  (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::NPCInkLoadingTest: test_ink_endpoint_should_return_application/json_content_type --------------------------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:25.965033"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:25.964391"], ["updated_at", "2025-11-21 11:13:25.964391"]] 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-21 11:13:25 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"security_guard", "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: security_guard [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 3ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:25.976490"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:25.975938"], ["updated_at", "2025-11-21 11:13:25.975938"]] 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-21 11:13:25 +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.9ms) 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:25.981047"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:25.980474"], ["updated_at", "2025-11-21 11:13:25.980474"]] 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-21 11:13:25 +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_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:25.984186"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:25.983620"], ["updated_at", "2025-11-21 11:13:25.983620"]] 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-21 11:13:25 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:25.987135"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:25.986595"], ["updated_at", "2025-11-21 11:13:25.986595"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:13:25 +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_handle_various_NPC_ID_formats -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:25.990250"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:25.989740"], ["updated_at", "2025-11-21 11:13:25.989740"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."handle" = ? LIMIT ? [["handle", "ink_test_user"], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::DemoUser Exists? (0.1ms) SELECT 1 AS one FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."handle" = ? LIMIT ? [["handle", "ink_test_user"], ["LIMIT", 1]] BreakEscape::DemoUser Create (0.1ms) INSERT INTO "break_escape_demo_users" ("handle", "role", "created_at", "updated_at") VALUES (?, ?, ?, ?) RETURNING "id" [["handle", "ink_test_user"], ["role", "user"], ["created_at", "2025-11-21 11:13:25.991694"], ["updated_at", "2025-11-21 11:13:25.991694"]] 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", 618102943], ["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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:25.992689"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:25.992162"], ["updated_at", "2025-11-21 11:13:25.992162"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/2/ink?npc=patrol_with_face" for 127.0.0.1 at 2025-11-21 11:13:25 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"patrol_with_face", "id"=>"2"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 618102943], ["LIMIT", 1]] Redirected to http://www.example.com/break_escape/ Completed 302 Found in 2ms (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-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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:25.997488"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:25.996920"], ["updated_at", "2025-11-21 11:13:25.996920"]] 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-21 11:13:25 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:26.000507"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:25.999945"], ["updated_at", "2025-11-21 11:13:25.999945"]] 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-21 11:13:26 +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:59: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:172: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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:26.141116"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:26.140594"], ["updated_at", "2025-11-21 11:13:26.140594"]] 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-21 11:13:26 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:26.144049"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:26.143571"], ["updated_at", "2025-11-21 11:13:26.143571"]] 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-21 11:13:26 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:26.146627"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:26.146130"], ["updated_at", "2025-11-21 11:13:26.146130"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:13:26 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:26.150033"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:26.149480"], ["updated_at", "2025-11-21 11:13:26.149480"]] 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-21 11:13:26 +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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_load_existing_NPC_ink_story_and_return_compiled_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:26.153519"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:26.153021"], ["updated_at", "2025-11-21 11:13:26.153021"]] 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-21 11:13:26 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:13:26.156767"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:13:26.156243"], ["updated_at", "2025-11-21 11:13:26.156243"]] 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-21 11:13:26 +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 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-21 11:14:29', '2025-11-21 11:14:29'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:14:29', '2025-11-21 11:14:29'); 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-21 11:14:29', '2025-11-21 11:14:29'); 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-21 11:14:29', '2025-11-21 11:14:29')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.7ms) commit transaction  (0.0ms) PRAGMA foreign_key_check TRANSACTION (0.0ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::NPCInkLoadingTest: test_npc-lazy-loader_should_construct_correct_API_endpoint_URL ---------------------------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.000175"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:29.999411"], ["updated_at", "2025-11-21 11:14:29.999411"]] 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-21 11:14:30 +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 (1.0ms) 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_ink_endpoint_should_handle_various_NPC_ID_formats -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.010347"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.009757"], ["updated_at", "2025-11-21 11:14:30.009757"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.011920"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.011418"], ["updated_at", "2025-11-21 11:14:30.011418"]] TRANSACTION (0.0ms) ROLLBACK TO SAVEPOINT active_record_1 TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::NPCInkLoadingTest: test_should_load_existing_NPC_ink_story_and_return_compiled_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.014452"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.013920"], ["updated_at", "2025-11-21 11:14:30.013920"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.015993"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.015478"], ["updated_at", "2025-11-21 11:14:30.015478"]] TRANSACTION (0.0ms) ROLLBACK TO SAVEPOINT active_record_1 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.018645"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.018087"], ["updated_at", "2025-11-21 11:14:30.018087"]] 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-21 11:14:30 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"security_guard", "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: security_guard [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 2ms (Views: 0.1ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.024825"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.024304"], ["updated_at", "2025-11-21 11:14:30.024304"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:14:30 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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-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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.028202"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.027665"], ["updated_at", "2025-11-21 11:14:30.027665"]] 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-21 11:14:30 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.031119"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.030565"], ["updated_at", "2025-11-21 11:14:30.030565"]] 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-21 11:14:30 +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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.035012"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.034429"], ["updated_at", "2025-11-21 11:14:30.034429"]] 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-21 11:14:30 +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:59: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:191: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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.181441"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.180895"], ["updated_at", "2025-11-21 11:14:30.180895"]] 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-21 11:14:30 +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.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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.184979"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.184432"], ["updated_at", "2025-11-21 11:14:30.184432"]] 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-21 11:14:30 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.188029"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.187530"], ["updated_at", "2025-11-21 11:14:30.187530"]] 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-21 11:14:30 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.190792"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.190321"], ["updated_at", "2025-11-21 11:14:30.190321"]] 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-21 11:14:30 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.193337"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.192822"], ["updated_at", "2025-11-21 11:14:30.192822"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:14:30 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:30.196379"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:30.195884"], ["updated_at", "2025-11-21 11:14:30.195884"]] 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-21 11:14:30 +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 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-21 11:14:36', '2025-11-21 11:14:36'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:14:36', '2025-11-21 11:14:36'); 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-21 11:14:36', '2025-11-21 11:14:36'); 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-21 11:14:36', '2025-11-21 11:14:36')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (1.8ms) commit transaction  (0.0ms) PRAGMA foreign_key_check TRANSACTION (0.0ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::NPCInkLoadingTest: test_should_return_404_for_NPC_without_story_file --------------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.202659"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.202022"], ["updated_at", "2025-11-21 11:14:36.202022"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:14:36 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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] Loading ink for NPC: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.214041"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.213478"], ["updated_at", "2025-11-21 11:14:36.213478"]] 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-21 11:14:36 +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 (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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.218824"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.218270"], ["updated_at", "2025-11-21 11:14:36.218270"]] 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-21 11:14:36 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.221709"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.221203"], ["updated_at", "2025-11-21 11:14:36.221203"]] 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-21 11:14:36 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.224895"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.224372"], ["updated_at", "2025-11-21 11:14:36.224372"]] 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-21 11:14:36 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.227458"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.226932"], ["updated_at", "2025-11-21 11:14:36.226932"]] 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-21 11:14:36 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.229995"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.229475"], ["updated_at", "2025-11-21 11:14:36.229475"]] 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-21 11:14:36 +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_should_load_existing_NPC_ink_story_and_return_compiled_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.232738"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.232159"], ["updated_at", "2025-11-21 11:14:36.232159"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.234352"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.233825"], ["updated_at", "2025-11-21 11:14:36.233825"]] TRANSACTION (0.0ms) ROLLBACK TO SAVEPOINT active_record_1 TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_handle_various_NPC_ID_formats -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.236811"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.236285"], ["updated_at", "2025-11-21 11:14:36.236285"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.238282"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.237770"], ["updated_at", "2025-11-21 11:14:36.237770"]] TRANSACTION (0.0ms) ROLLBACK TO SAVEPOINT active_record_1 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.240575"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.240047"], ["updated_at", "2025-11-21 11:14:36.240047"]] 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-21 11:14:36 +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:59: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:191: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.1ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.402478"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.401950"], ["updated_at", "2025-11-21 11:14:36.401950"]] 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-21 11:14:36 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.405452"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.404961"], ["updated_at", "2025-11-21 11:14:36.404961"]] 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-21 11:14:36 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.407973"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.407517"], ["updated_at", "2025-11-21 11:14:36.407517"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:14:36 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:14:36.410823"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:14:36.410357"], ["updated_at", "2025-11-21 11:14:36.410357"]] 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-21 11:14:36 +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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 1ms (Views: 0.0ms | 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-21 11:15:08', '2025-11-21 11:15:08'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:15:08', '2025-11-21 11:15: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-21 11:15:08', '2025-11-21 11:15: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-21 11:15:08', '2025-11-21 11:15:08')  (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::NPCInkLoadingTest: test_npc-manager_should_load_stories_via_API_endpoint ------------------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:08.793035"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:08.792394"], ["updated_at", "2025-11-21 11:15:08.792394"]] 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-21 11:15:08 +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 (1.1ms) 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:08.803273"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:08.802698"], ["updated_at", "2025-11-21 11:15:08.802698"]] 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-21 11:15:08 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:08.806298"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:08.805782"], ["updated_at", "2025-11-21 11:15:08.805782"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:15:08 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"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]] Completed 400 Bad Request in 2ms (Views: 0.1ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:08.811770"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:08.811251"], ["updated_at", "2025-11-21 11:15:08.811251"]] 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-21 11:15: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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:08.814876"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:08.814297"], ["updated_at", "2025-11-21 11:15:08.814297"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:15:08 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:08.818515"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:08.817979"], ["updated_at", "2025-11-21 11:15:08.817979"]] 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-21 11:15:08 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:08.821280"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:08.820731"], ["updated_at", "2025-11-21 11:15:08.820731"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:15:08 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:08.824439"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:08.823920"], ["updated_at", "2025-11-21 11:15:08.823920"]] 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-21 11:15:08 +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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:08.826985"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:08.826468"], ["updated_at", "2025-11-21 11:15:08.826468"]] 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-21 11:15: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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:08.834366"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:08.833765"], ["updated_at", "2025-11-21 11:15:08.833765"]] 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-21 11:15: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:59: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.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:08.995041"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:08.994512"], ["updated_at", "2025-11-21 11:15:08.994512"]] 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-21 11:15: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.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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:08.998492"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:08.997882"], ["updated_at", "2025-11-21 11:15:08.997882"]] 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-21 11:15:08 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:09.001680"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:09.001165"], ["updated_at", "2025-11-21 11:15:09.001165"]] 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-21 11:15: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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 1ms (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-21 11:15:13', '2025-11-21 11:15:13'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:15:13', '2025-11-21 11:15:13'); 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-21 11:15:13', '2025-11-21 11:15:13'); 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-21 11:15:13', '2025-11-21 11:15:13')  (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::NPCInkLoadingTest: test_ink_endpoint_should_work_with_underscored_NPC_IDs -------------------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:13.965794"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:13.965007"], ["updated_at", "2025-11-21 11:15:13.965007"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:15:13 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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] Loading ink for NPC: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:13.977399"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:13.976878"], ["updated_at", "2025-11-21 11:15:13.976878"]] 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-21 11:15:13 +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_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:13.981723"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:13.981177"], ["updated_at", "2025-11-21 11:15:13.981177"]] 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-21 11:15:13 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:13.985600"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:13.985037"], ["updated_at", "2025-11-21 11:15:13.985037"]] 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-21 11:15:13 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:13.988329"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:13.987819"], ["updated_at", "2025-11-21 11:15:13.987819"]] 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-21 11:15:13 +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.1ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:13.991012"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:13.990495"], ["updated_at", "2025-11-21 11:15:13.990495"]] 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-21 11:15:13 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:13.993649"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:13.993129"], ["updated_at", "2025-11-21 11:15:13.993129"]] 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-21 11:15:13 +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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:13.996175"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:13.995664"], ["updated_at", "2025-11-21 11:15:13.995664"]] 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-21 11:15:13 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:13.999155"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:13.998569"], ["updated_at", "2025-11-21 11:15:13.998569"]] 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-21 11:15: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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:14.003101"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:14.002537"], ["updated_at", "2025-11-21 11:15:14.002537"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:15: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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:14.006159"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:14.005639"], ["updated_at", "2025-11-21 11:15:14.005639"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:15:14 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:14.009272"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:14.008755"], ["updated_at", "2025-11-21 11:15:14.008755"]] 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-21 11:15: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:59: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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:14.171922"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:14.171404"], ["updated_at", "2025-11-21 11:15:14.171404"]] 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-21 11:15: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.1ms) 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-21 11:15:50', '2025-11-21 11:15:50'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:15:50', '2025-11-21 11:15:50'); 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-21 11:15:50', '2025-11-21 11:15:50'); 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-21 11:15:50', '2025-11-21 11:15:50')  (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_ink_endpoint_should_require_npc_parameter -------------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.726283"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.725678"], ["updated_at", "2025-11-21 11:15:50.725678"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:15:50 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"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]] Completed 400 Bad Request in 3ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.1ms) TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------------------ BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_compiled_Ink_JSON_for_existing_story ------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.738240"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.737643"], ["updated_at", "2025-11-21 11:15:50.737643"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.739804"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.739285"], ["updated_at", "2025-11-21 11:15:50.739285"]] TRANSACTION (0.0ms) ROLLBACK TO SAVEPOINT active_record_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.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.742334"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.741760"], ["updated_at", "2025-11-21 11:15:50.741760"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-21 11:15:50 +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.2ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.746014"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.745475"], ["updated_at", "2025-11-21 11:15:50.745475"]] 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-21 11:15:50 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.749575"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.748989"], ["updated_at", "2025-11-21 11:15:50.748989"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:15:50 +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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 6ms (Views: 3.0ms | 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 ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.758646"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.758087"], ["updated_at", "2025-11-21 11:15:50.758087"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-21 11:15:50 +0000 Processing by BreakEscape::Api::GamesController#sync_state as HTML Parameters: {"currentRoom"=>"office", "id"=>"1"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* 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]] BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"office\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:15:50.763798"], ["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.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_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.766105"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.765483"], ["updated_at", "2025-11-21 11:15:50.765483"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-21 11:15:50 +0000 Processing by BreakEscape::Api::GamesController#inventory as HTML Parameters: {"action_type"=>"add", "item"=>{"type"=>"key", "name"=>"Test Key", "id"=>"test_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]] 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\":\"key\",\"name\":\"Test Key\",\"id\":\"test_key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:15:50.768663"], ["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.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_handle_URL-encoded_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.770676"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.770118"], ["updated_at", "2025-11-21 11:15:50.770118"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.772175"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.771638"], ["updated_at", "2025-11-21 11:15:50.771638"]] 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.774421"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.773896"], ["updated_at", "2025-11-21 11:15:50.773896"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:15:50 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.777754"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.777244"], ["updated_at", "2025-11-21 11:15:50.777244"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:15:50 +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.0ms) TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.782531"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.781917"], ["updated_at", "2025-11-21 11:15:50.781917"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.784202"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.783636"], ["updated_at", "2025-11-21 11:15:50.783636"]] 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_work_with_game_bootstrap ----------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.789597"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.786252"], ["updated_at", "2025-11-21 11:15:50.786252"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-21 11:15:50 +0000 Processing by BreakEscape::Api::GamesController#bootstrap 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]] Completed 200 OK in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.2ms) TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.793199"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.792519"], ["updated_at", "2025-11-21 11:15:50.792519"]] TRANSACTION (0.0ms) ROLLBACK TO SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.795448"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.794881"], ["updated_at", "2025-11-21 11:15:50.794881"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 11:15:50 +0000 Processing by BreakEscape::Api::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]] Completed 422 Unprocessable Content 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.799112"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.798465"], ["updated_at", "2025-11-21 11:15:50.798465"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:15:50 +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_bootstrap_endpoint_should_return_game_state ---------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:15:50.803711"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:15:50.803085"], ["updated_at", "2025-11-21 11:15:50.803085"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-21 11:15:50 +0000 Processing by BreakEscape::Api::GamesController#bootstrap 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]] Completed 200 OK in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (4 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-21 11:16:00', '2025-11-21 11:16:00'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:16:00', '2025-11-21 11:16:00'); 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-21 11:16:00', '2025-11-21 11:16:00'); 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-21 11:16:00', '2025-11-21 11:16:00')  (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::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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.608652"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.607929"], ["updated_at", "2025-11-21 11:16:00.607929"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 11:16:00 +0000 Processing by BreakEscape::Api::GamesController#unlock as HTML Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "method"=>"keypad", "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]] Completed 422 Unprocessable Content in 4ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.1ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.622249"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.621665"], ["updated_at", "2025-11-21 11:16:00.621665"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-21 11:16:00 +0000 Processing by BreakEscape::Api::GamesController#inventory as HTML Parameters: {"action_type"=>"add", "item"=>{"type"=>"key", "name"=>"Test Key", "id"=>"test_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]] 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\":\"key\",\"name\":\"Test Key\",\"id\":\"test_key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:16:00.624929"], ["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::GamesControllerTest: test_bootstrap_endpoint_should_return_game_state ---------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.627091"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.626530"], ["updated_at", "2025-11-21 11:16:00.626530"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-21 11:16:00 +0000 Processing by BreakEscape::Api::GamesController#bootstrap 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]] Completed 200 OK in 1ms (Views: 0.1ms | 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_compiled_Ink_JSON_for_existing_story ------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.630929"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.630324"], ["updated_at", "2025-11-21 11:16:00.630324"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.632663"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.632034"], ["updated_at", "2025-11-21 11:16:00.632034"]] 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.635219"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.634685"], ["updated_at", "2025-11-21 11:16:00.634685"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:16:00 +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.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 ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.639437"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.638912"], ["updated_at", "2025-11-21 11:16:00.638912"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-21 11:16:00 +0000 Processing by BreakEscape::Api::GamesController#sync_state as HTML Parameters: {"currentRoom"=>"office", "id"=>"1"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* 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]] BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"office\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:16:00.641561"], ["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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.643379"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.642840"], ["updated_at", "2025-11-21 11:16:00.642840"]] 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-21 11:16:00 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.646760"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.646203"], ["updated_at", "2025-11-21 11:16:00.646203"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:16:00 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_handle_URL-encoded_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.650393"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.649815"], ["updated_at", "2025-11-21 11:16:00.649815"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.651937"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.651431"], ["updated_at", "2025-11-21 11:16:00.651431"]] TRANSACTION (0.0ms) ROLLBACK TO 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.654197"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.653650"], ["updated_at", "2025-11-21 11:16:00.653650"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:16:00 +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.6ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 5ms (Views: 3.0ms | 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.663541"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.662935"], ["updated_at", "2025-11-21 11:16:00.662935"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:16:00 +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.4ms | ActiveRecord: 0.1ms (4 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.668149"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.667576"], ["updated_at", "2025-11-21 11:16:00.667576"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:16:00 +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.2ms) TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_ink_endpoint_should_work_with_game_bootstrap ----------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.675427"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.674732"], ["updated_at", "2025-11-21 11:16:00.674732"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-21 11:16:00 +0000 Processing by BreakEscape::Api::GamesController#bootstrap 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]] Completed 200 OK in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.678437"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.677876"], ["updated_at", "2025-11-21 11:16:00.677876"]] TRANSACTION (0.0ms) ROLLBACK TO SAVEPOINT active_record_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.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.680876"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.680318"], ["updated_at", "2025-11-21 11:16:00.680318"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-21 11:16:00 +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.2ms | 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.685043"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.684504"], ["updated_at", "2025-11-21 11:16:00.684504"]] 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:16:00.686594"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:16:00.686117"], ["updated_at", "2025-11-21 11:16:00.686117"]] 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-21 11:17:16', '2025-11-21 11:17:16'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:17:16', '2025-11-21 11:17:16'); 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-21 11:17:16', '2025-11-21 11:17:16'); 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-21 11:17:16', '2025-11-21 11:17:16')  (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_show_should_return_HTML_with_game_container ---------------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:16.995010"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:16.994255"], ["updated_at", "2025-11-21 11:17:16.994255"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:17:16 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"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::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.6ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 8ms (Views: 3.0ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ---------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:17.013191"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:17.012540"], ["updated_at", "2025-11-21 11:17:17.012540"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-21 11:17:17 +0000 Processing by BreakEscape::Api::GamesController#sync_state as HTML Parameters: {"currentRoom"=>"office", "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]] BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"office\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:17:17.018676"], ["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.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_bootstrap_endpoint_should_return_game_state ---------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:17.021083"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:17.020502"], ["updated_at", "2025-11-21 11:17:17.020502"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-21 11:17:17 +0000 Processing by BreakEscape::Api::GamesController#bootstrap 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]] Completed 200 OK in 1ms (Views: 0.1ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:17.024834"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:17.024279"], ["updated_at", "2025-11-21 11:17:17.024279"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:17:17 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:17.028215"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:17.027659"], ["updated_at", "2025-11-21 11:17:17.027659"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:17:17 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:17.031625"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:17.031048"], ["updated_at", "2025-11-21 11:17:17.031048"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 11:17:17 +0000 Processing by BreakEscape::Api::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]] Completed 422 Unprocessable Content 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:17.035844"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:17.035241"], ["updated_at", "2025-11-21 11:17:17.035241"]] 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-21 11:17:17 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:17.039399"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:17.038871"], ["updated_at", "2025-11-21 11:17:17.038871"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-21 11:17:17 +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.2ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:17.042955"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:17.042425"], ["updated_at", "2025-11-21 11:17:17.042425"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-21 11:17:17 +0000 Processing by BreakEscape::Api::GamesController#inventory as HTML Parameters: {"action_type"=>"add", "item"=>{"type"=>"key", "name"=>"Test Key", "id"=>"test_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]] 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\":\"key\",\"name\":\"Test Key\",\"id\":\"test_key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:17:17.045184"], ["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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:17.047190"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:17.046604"], ["updated_at", "2025-11-21 11:17:17.046604"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:17:17 +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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:17.051789"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:17.051184"], ["updated_at", "2025-11-21 11:17:17.051184"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:17:17 +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 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-21 11:17:39', '2025-11-21 11:17:39'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:17:39', '2025-11-21 11:17: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-21 11:17:39', '2025-11-21 11:17: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-21 11:17:39', '2025-11-21 11:17:39')  (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::GamesControllerTest: test_bootstrap_endpoint_should_return_game_state ---------------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.602669"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.601966"], ["updated_at", "2025-11-21 11:17:39.601966"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-21 11:17:39 +0000 Processing by BreakEscape::Api::GamesController#bootstrap as HTML Parameters: {"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::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.1ms (4 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.614612"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.614007"], ["updated_at", "2025-11-21 11:17:39.614007"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-21 11:17: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.2ms | 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 ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.619540"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.619006"], ["updated_at", "2025-11-21 11:17:39.619006"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-21 11:17:39 +0000 Processing by BreakEscape::Api::GamesController#sync_state as HTML Parameters: {"currentRoom"=>"office", "id"=>"1"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* 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]] BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"office\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:17:39.623425"], ["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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.625571"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.625021"], ["updated_at", "2025-11-21 11:17:39.625021"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-21 11:17:39 +0000 Processing by BreakEscape::Api::GamesController#inventory as HTML Parameters: {"action_type"=>"add", "item"=>{"type"=>"key", "name"=>"Test Key", "id"=>"test_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]] 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\":\"key\",\"name\":\"Test Key\",\"id\":\"test_key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:17:39.627780"], ["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::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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.629872"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.629246"], ["updated_at", "2025-11-21 11:17:39.629246"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 11:17:39 +0000 Processing by BreakEscape::Api::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]] Completed 422 Unprocessable Content 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_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.633669"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.633048"], ["updated_at", "2025-11-21 11:17:39.633048"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:17: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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.637326"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.636760"], ["updated_at", "2025-11-21 11:17:39.636760"]] 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-21 11:17: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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.640641"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.640106"], ["updated_at", "2025-11-21 11:17:39.640106"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:17: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: 1.7ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.9ms | GC: 0.0ms) Completed 200 OK in 6ms (Views: 3.1ms | ActiveRecord: 0.1ms (4 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.650169"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.649489"], ["updated_at", "2025-11-21 11:17:39.649489"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:17: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.4ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.654637"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.654081"], ["updated_at", "2025-11-21 11:17:39.654081"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:17:39 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.660941"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.660410"], ["updated_at", "2025-11-21 11:17:39.660410"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:17: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.4ms | ActiveRecord: 0.1ms (4 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.665518"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.664896"], ["updated_at", "2025-11-21 11:17:39.664896"]] 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-21 11:17: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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 1ms (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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.669436"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.668906"], ["updated_at", "2025-11-21 11:17:39.668906"]] 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-21 11:17: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.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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.673003"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.672513"], ["updated_at", "2025-11-21 11:17:39.672513"]] 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-21 11:17: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:59: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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.811067"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.810569"], ["updated_at", "2025-11-21 11:17:39.810569"]] 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-21 11:17: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.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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.814367"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.813829"], ["updated_at", "2025-11-21 11:17:39.813829"]] 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-21 11:17: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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.817569"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.817051"], ["updated_at", "2025-11-21 11:17:39.817051"]] 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-21 11:17: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.0ms) Completed 200 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.820304"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.819815"], ["updated_at", "2025-11-21 11:17:39.819815"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:17:39 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.823428"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.822935"], ["updated_at", "2025-11-21 11:17:39.822935"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:17: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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.826328"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.825853"], ["updated_at", "2025-11-21 11:17:39.825853"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:17:39 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.830228"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.828753"], ["updated_at", "2025-11-21 11:17:39.828753"]] 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-21 11:17: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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.2ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.834620"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.833873"], ["updated_at", "2025-11-21 11:17:39.833873"]] 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-21 11:17: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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.837763"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.837238"], ["updated_at", "2025-11-21 11:17:39.837238"]] 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-21 11:17: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 (0.0ms) Completed 200 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:17:39.840605"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:17:39.840034"], ["updated_at", "2025-11-21 11:17:39.840034"]] 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-21 11:17: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.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-21 11:18:12', '2025-11-21 11:18:12'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:18:12', '2025-11-21 11:18:12'); 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-21 11:18:12', '2025-11-21 11:18:12'); 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-21 11:18:12', '2025-11-21 11:18:12')  (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::NPCInkLoadingTest: test_ink_endpoint_should_return_application/json_content_type --------------------------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.554941"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.554312"], ["updated_at", "2025-11-21 11:18:12.554312"]] 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-21 11:18:12 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"security_guard", "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: security_guard [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 3ms (Views: 0.1ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.566394"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.565826"], ["updated_at", "2025-11-21 11:18:12.565826"]] 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-21 11:18:12 +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 (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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.571108"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.570567"], ["updated_at", "2025-11-21 11:18:12.570567"]] 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-21 11:18:12 +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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.573879"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.573342"], ["updated_at", "2025-11-21 11:18:12.573342"]] 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-21 11:18:12 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.576637"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.576065"], ["updated_at", "2025-11-21 11:18:12.576065"]] 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-21 11:18:12 +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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.579888"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.579361"], ["updated_at", "2025-11-21 11:18:12.579361"]] 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-21 11:18:12 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.582684"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.582147"], ["updated_at", "2025-11-21 11:18:12.582147"]] 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-21 11:18:12 +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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.585905"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.585294"], ["updated_at", "2025-11-21 11:18:12.585294"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:18:12 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.589107"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.588570"], ["updated_at", "2025-11-21 11:18:12.588570"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:18:12 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.592260"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.591728"], ["updated_at", "2025-11-21 11:18:12.591728"]] 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-21 11:18:12 +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:59: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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.754431"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.753909"], ["updated_at", "2025-11-21 11:18:12.753909"]] 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-21 11:18:12 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.757300"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.756816"], ["updated_at", "2025-11-21 11:18:12.756816"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:18:12 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.760746"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.760193"], ["updated_at", "2025-11-21 11:18:12.760193"]] 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-21 11:18:12 +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::GamesControllerTest: test_bootstrap_endpoint_should_return_game_state ---------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.763717"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.763219"], ["updated_at", "2025-11-21 11:18:12.763219"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-21 11:18:12 +0000 Processing by BreakEscape::Api::GamesController#bootstrap 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]] Completed 200 OK in 1ms (Views: 0.1ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.768107"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.767621"], ["updated_at", "2025-11-21 11:18:12.767621"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-21 11:18:12 +0000 Processing by BreakEscape::Api::GamesController#inventory as HTML Parameters: {"action_type"=>"add", "item"=>{"type"=>"key", "name"=>"Test Key", "id"=>"test_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]] 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\":\"key\",\"name\":\"Test Key\",\"id\":\"test_key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:18:12.773279"], ["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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.775332"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.774826"], ["updated_at", "2025-11-21 11:18:12.774826"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:18:12 +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.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: 1.1ms | ActiveRecord: 0.1ms (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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.781228"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.780646"], ["updated_at", "2025-11-21 11:18:12.780646"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:18:12 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.784803"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.784193"], ["updated_at", "2025-11-21 11:18:12.784193"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:18:12 +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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.788478"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.788000"], ["updated_at", "2025-11-21 11:18:12.788000"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-21 11:18:12 +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.2ms | 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 ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.791874"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.791344"], ["updated_at", "2025-11-21 11:18:12.791344"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-21 11:18:12 +0000 Processing by BreakEscape::Api::GamesController#sync_state as HTML Parameters: {"currentRoom"=>"office", "id"=>"1"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* 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]] BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"office\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:18:12.794070"], ["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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.796079"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.795539"], ["updated_at", "2025-11-21 11:18:12.795539"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 11:18:12 +0000 Processing by BreakEscape::Api::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]] Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.799467"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.798970"], ["updated_at", "2025-11-21 11:18:12.798970"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:18:12 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.803650"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.803183"], ["updated_at", "2025-11-21 11:18:12.803183"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:18:12 +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.1ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.806613"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.806139"], ["updated_at", "2025-11-21 11:18:12.806139"]] 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-21 11:18:12 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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 --------------------------------------------- BreakEscapeTest: test_it_has_a_version_number --------------------------------------------- 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-21 11:18:12 +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_Headers:_should_include_Cache-Control ---------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 11:18:12 +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-21 11:18:12 +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.3ms | 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-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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_nested_files ------------------------------------------------------------------------------ Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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_Integrity:_audio_files_are_non-empty --------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-21 11:18:12 +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:_CSS_files_are_non-empty ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 11:18:12 +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_return_404_for_non-existent_files ------------------------------------------------------------------------------------------- Started GET "/break_escape/non-existent.html" for 127.0.0.1 at 2025-11-21 11:18:12 +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_Routes:_should_capture_complex_paths_with_segments ----------------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 11:18:12 +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-21 11:18:12 +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_Minigame:_should_serve_lockpicking_script -------------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 11:18:12 +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:_image_files_are_non-empty --------------------------------------------------------------------------------- Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 11:18:12 +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_return_404_for_non-existent_files --------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/non-existent.mp3" for 127.0.0.1 at 2025-11-21 11:18:12 +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_CSS:_should_serve_with_inline_disposition -------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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_set_Content-Disposition_to_inline ---------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 11:18:12 +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_Routes:_should_capture_full_filename_with_extension ------------------------------------------------------------------------------------------------ Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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:_JavaScript_files_are_non-empty -------------------------------------------------------------------------------------- Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 11:18:12 +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_JS ----------------------------------------------------------------------------------------------- Started GET "/break_escape/js/../../config/secrets.yml" for 127.0.0.1 at 2025-11-21 11:18:12 +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_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-21 11:18:12 +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_HTML:_should_serve_test_files_with_correct_MIME_type ------------------------------------------------------------------------------------------------- Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 11:18:12 +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_JS:_should_serve_core_game_module ------------------------------------------------------------------------------ Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-21 11:18:12 +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-21 11:18:12 +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_CSS_files_should_be_accessible_from_main_game -------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 11:18:12 +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_lockpicking_minigame -------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 11:18:12 +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_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-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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.1ms) Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) Started GET "/break_escape/assets/sounds/lockpick_reset.mp3" for 127.0.0.1 at 2025-11-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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_GAME_CONFIG_with_proper_baseURL ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 11:18:12 +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-21 11:18:12 +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.1ms) Started GET "/break_escape/js/../../config/database.yml" for 127.0.0.1 at 2025-11-21 11:18:12 +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-21 11:18:12 +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_route_constraints_correctly_capture_file_extensions -------------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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_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-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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_minigame_starters ----------------------------------------------------------------------------- Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-21 11:18:12 +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_key-operations_minigame_module ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/minigames/lockpicking/key-operations.js" for 127.0.0.1 at 2025-11-21 11:18:12 +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_load_all_required_game_files_in_correct_order --------------------------------------------------------------------------------------------------- Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 11:18:12 +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_all_response_headers_are_correct ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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-21 11:18:12 +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_test_asset_page_loads_correctly ------------------------------------------------------------------------------ Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 11:18:12 +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::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_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") VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["name", "test"], ["display_name", "Test"], ["description", nil], ["published", 0], ["difficulty_level", 1], ["created_at", "2025-11-21 11:18:12.891865"], ["updated_at", "2025-11-21 11:18:12.891865"]] 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::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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.893938"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.893359"], ["updated_at", "2025-11-21 11:18:12.893359"]] 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-21 11:18:12.895009"], ["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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.896531"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.896030"], ["updated_at", "2025-11-21 11:18:12.896030"]] 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-21 11:18:12.897454"], ["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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.898887"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.898387"], ["updated_at", "2025-11-21 11:18:12.898387"]] 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.901864"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.900256"], ["updated_at", "2025-11-21 11:18:12.900256"]] 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-21 11:18:12.902890"], ["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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.904468"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.903963"], ["updated_at", "2025-11-21 11:18:12.903963"]] 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-21 11:18:12.905712"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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.2ms) SELECT COUNT(*) FROM "break_escape_games" Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-21 11:18:12 +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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.909732"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.908999"], ["updated_at", "2025-11-21 11:18:12.908999"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 3ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.2ms) 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.1ms) 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-21 11:18:12 +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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:12.915230"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:12.914253"], ["updated_at", "2025-11-21 11:18:12.914253"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 3ms (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_display_published_missions --------------------------------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-21 11:18:12 +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 Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.4ms | 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 (2 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::MissionsControllerTest: test_index_should_return_HTML_with_mission_list ------------------------------------------------------------------------------------ Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-21 11:18:12 +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 Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.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 (2 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-21 11:18:12 +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 Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.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.4ms | ActiveRecord: 0.0ms (2 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_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_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_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_determines_HTML_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_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::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_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_PNG_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-21 11:18:14', '2025-11-21 11:18:14'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:18:14', '2025-11-21 11:18: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-21 11:18:14', '2025-11-21 11:18: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-21 11:18:14', '2025-11-21 11:18:14')  (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::NPCInkLoadingTest: test_ink_endpoint_should_return_application/json_content_type --------------------------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.016484"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.015849"], ["updated_at", "2025-11-21 11:18:15.015849"]] 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-21 11:18:15 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"security_guard", "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: security_guard [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.028022"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.027373"], ["updated_at", "2025-11-21 11:18:15.027373"]] 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-21 11:18:15 +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 (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_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.033186"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.032626"], ["updated_at", "2025-11-21 11:18:15.032626"]] 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-21 11:18:15 +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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.036308"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.035647"], ["updated_at", "2025-11-21 11:18:15.035647"]] 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-21 11:18:15 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.039563"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.039011"], ["updated_at", "2025-11-21 11:18:15.039011"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:18:15 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.043025"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.042485"], ["updated_at", "2025-11-21 11:18:15.042485"]] 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-21 11:18:15 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.046062"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.045506"], ["updated_at", "2025-11-21 11:18:15.045506"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:18:15 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.050475"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.049886"], ["updated_at", "2025-11-21 11:18:15.049886"]] 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-21 11:18:15 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.053711"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.053152"], ["updated_at", "2025-11-21 11:18:15.053152"]] 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-21 11:18:15 +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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.057090"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.056545"], ["updated_at", "2025-11-21 11:18:15.056545"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:18:15 +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.1ms | 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.060239"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.059638"], ["updated_at", "2025-11-21 11:18:15.059638"]] 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-21 11:18:15 +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:59: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.1ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.204320"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.203789"], ["updated_at", "2025-11-21 11:18:15.203789"]] 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-21 11:18:15 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.207406"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.206903"], ["updated_at", "2025-11-21 11:18:15.206903"]] 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-21 11:18:15 +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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.210502"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.209969"], ["updated_at", "2025-11-21 11:18:15.209969"]] 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-21 11:18:15 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_bootstrap_endpoint_should_return_game_state ---------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.214198"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.213692"], ["updated_at", "2025-11-21 11:18:15.213692"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-21 11:18:15 +0000 Processing by BreakEscape::Api::GamesController#bootstrap 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]] Completed 200 OK in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (4 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.219039"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.218514"], ["updated_at", "2025-11-21 11:18:15.218514"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-21 11:18:15 +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 2ms (Views: 1.6ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 1.3ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.224069"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.223537"], ["updated_at", "2025-11-21 11:18:15.223537"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:18:15 +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.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: 1.1ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.2ms) 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.230029"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.229502"], ["updated_at", "2025-11-21 11:18:15.229502"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:18:15 +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.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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.235123"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.234565"], ["updated_at", "2025-11-21 11:18:15.234565"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:18:15 +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.1ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.238812"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.238234"], ["updated_at", "2025-11-21 11:18:15.238234"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:18:15 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.242195"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.241710"], ["updated_at", "2025-11-21 11:18:15.241710"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 11:18:15 +0000 Processing by BreakEscape::Api::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]] Completed 422 Unprocessable Content 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 ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.247977"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.247427"], ["updated_at", "2025-11-21 11:18:15.247427"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-21 11:18:15 +0000 Processing by BreakEscape::Api::GamesController#sync_state as HTML Parameters: {"currentRoom"=>"office", "id"=>"1"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* 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]] BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"office\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:18:15.250531"], ["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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.252656"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.252165"], ["updated_at", "2025-11-21 11:18:15.252165"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-21 11:18:15 +0000 Processing by BreakEscape::Api::GamesController#inventory as HTML Parameters: {"action_type"=>"add", "item"=>{"type"=>"key", "name"=>"Test Key", "id"=>"test_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]] 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\":\"key\",\"name\":\"Test Key\",\"id\":\"test_key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:18:15.255014"], ["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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:18:15.256932"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:18:15.256373"], ["updated_at", "2025-11-21 11:18:15.256373"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:18:15 +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 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-21 11:19:48', '2025-11-21 11:19:48'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:19:48', '2025-11-21 11:19:48'); 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-21 11:19:48', '2025-11-21 11:19:48'); 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-21 11:19:48', '2025-11-21 11:19:48')  (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::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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.603573"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.602800"], ["updated_at", "2025-11-21 11:19:48.602800"]] 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-21 11:19:48 +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.2ms) Completed 200 OK in 2ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::NPCInkLoadingTest: test_npc-lazy-loader_should_construct_correct_API_endpoint_URL ---------------------------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.616413"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.615814"], ["updated_at", "2025-11-21 11:19:48.615814"]] 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-21 11:19:48 +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-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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.620466"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.619605"], ["updated_at", "2025-11-21 11:19:48.619605"]] 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-21 11:19:48 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.624122"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.623542"], ["updated_at", "2025-11-21 11:19:48.623542"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:19:48 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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] Loading ink for NPC: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 3ms (Views: 0.1ms | 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.630638"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.630028"], ["updated_at", "2025-11-21 11:19:48.630028"]] 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-21 11:19:48 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.634116"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.633552"], ["updated_at", "2025-11-21 11:19:48.633552"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:19:48 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.637631"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.637084"], ["updated_at", "2025-11-21 11:19:48.637084"]] 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-21 11:19:48 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.640388"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.639855"], ["updated_at", "2025-11-21 11:19:48.639855"]] 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-21 11:19:48 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.643067"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.642524"], ["updated_at", "2025-11-21 11:19:48.642524"]] 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-21 11:19:48 +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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.646660"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.646060"], ["updated_at", "2025-11-21 11:19:48.646060"]] 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-21 11:19:48 +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:59: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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.792149"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.791636"], ["updated_at", "2025-11-21 11:19:48.791636"]] 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-21 11:19:48 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.795277"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.794764"], ["updated_at", "2025-11-21 11:19:48.794764"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:19:48 +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.1ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.799010"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.798459"], ["updated_at", "2025-11-21 11:19:48.798459"]] 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-21 11:19:48 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.802535"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.802039"], ["updated_at", "2025-11-21 11:19:48.802039"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:19:48 +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: 1.0ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.807558"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.807044"], ["updated_at", "2025-11-21 11:19:48.807044"]] 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-21 11:19:48 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.810678"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.810146"], ["updated_at", "2025-11-21 11:19:48.810146"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:19:48 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 2ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 1.6ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.816257"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.815633"], ["updated_at", "2025-11-21 11:19:48.815633"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:19:48 +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.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.2ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.820137"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.819626"], ["updated_at", "2025-11-21 11:19:48.819626"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-21 11:19:48 +0000 Processing by BreakEscape::Api::GamesController#inventory as HTML Parameters: {"action_type"=>"add", "item"=>{"type"=>"key", "name"=>"Test Key", "id"=>"test_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]] 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\":\"key\",\"name\":\"Test Key\",\"id\":\"test_key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:19:48.824826"], ["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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.826797"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.826322"], ["updated_at", "2025-11-21 11:19:48.826322"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:19:48 +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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.831292"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.830704"], ["updated_at", "2025-11-21 11:19:48.830704"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:19:48 +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 ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.835974"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.835468"], ["updated_at", "2025-11-21 11:19:48.835468"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-21 11:19:48 +0000 Processing by BreakEscape::Api::GamesController#sync_state as HTML Parameters: {"currentRoom"=>"office", "id"=>"1"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* 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]] BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"office\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:19:48.838202"], ["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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.840119"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.839525"], ["updated_at", "2025-11-21 11:19:48.839525"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-21 11:19:48 +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.2ms | 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.843547"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.843060"], ["updated_at", "2025-11-21 11:19:48.843060"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 11:19:48 +0000 Processing by BreakEscape::Api::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]] 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_bootstrap_endpoint_should_return_game_state ---------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:48.847189"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:48.846615"], ["updated_at", "2025-11-21 11:19:48.846615"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-21 11:19:48 +0000 Processing by BreakEscape::Api::GamesController#bootstrap 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]] Completed 200 OK in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (4 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-21 11:19:57', '2025-11-21 11:19:57'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:19:57', '2025-11-21 11:19:57'); 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-21 11:19:57', '2025-11-21 11:19:57'); 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-21 11:19:57', '2025-11-21 11:19:57')  (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::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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:57.857123"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:57.856462"], ["updated_at", "2025-11-21 11:19:57.856462"]] 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-21 11:19:57 +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.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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:57.867350"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:57.866798"], ["updated_at", "2025-11-21 11:19:57.866798"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:19:57 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"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]] Completed 400 Bad Request in 2ms (Views: 0.1ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:57.873101"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:57.872559"], ["updated_at", "2025-11-21 11:19:57.872559"]] 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-21 11:19:57 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:57.875923"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:57.875308"], ["updated_at", "2025-11-21 11:19:57.875308"]] 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-21 11:19:57 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:57.878618"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:57.878063"], ["updated_at", "2025-11-21 11:19:57.878063"]] 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-21 11:19:57 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:57.883049"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:57.882432"], ["updated_at", "2025-11-21 11:19:57.882432"]] 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-21 11:19:57 +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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:57.886935"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:57.886353"], ["updated_at", "2025-11-21 11:19:57.886353"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:19:57 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:57.890920"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:57.890308"], ["updated_at", "2025-11-21 11:19:57.890308"]] 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-21 11:19:57 +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_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:57.894286"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:57.893711"], ["updated_at", "2025-11-21 11:19:57.893711"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:19:57 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:57.898963"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:57.898327"], ["updated_at", "2025-11-21 11:19:57.898327"]] 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-21 11:19:57 +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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:57.902396"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:57.901826"], ["updated_at", "2025-11-21 11:19:57.901826"]] 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-21 11:19:57 +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-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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:57.905730"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:57.905154"], ["updated_at", "2025-11-21 11:19:57.905154"]] 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-21 11:19:57 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:57.909142"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:57.908551"], ["updated_at", "2025-11-21 11:19:57.908551"]] 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-21 11:19:57 +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:59: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::GamesControllerTest: test_ink_endpoint_should_return_404_for_NPC_without_story_file ------------------------------------------------------------------------------------------------ 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\":\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:58.071270"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:58.070649"], ["updated_at", "2025-11-21 11:19:58.070649"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:19:58 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:58.075146"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:58.074670"], ["updated_at", "2025-11-21 11:19:58.074670"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-21 11:19:58 +0000 Processing by BreakEscape::Api::GamesController#inventory as HTML Parameters: {"action_type"=>"add", "item"=>{"type"=>"key", "name"=>"Test Key", "id"=>"test_key"}, "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* 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]] 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\":\"key\",\"name\":\"Test Key\",\"id\":\"test_key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:19:58.080184"], ["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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:58.082451"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:58.081916"], ["updated_at", "2025-11-21 11:19:58.081916"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 11:19:58 +0000 Processing by BreakEscape::Api::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]] 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_bootstrap_endpoint_should_return_game_state ---------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:58.085730"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:58.085243"], ["updated_at", "2025-11-21 11:19:58.085243"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-21 11:19:58 +0000 Processing by BreakEscape::Api::GamesController#bootstrap 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]] Completed 200 OK in 1ms (Views: 0.1ms | 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 ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:58.088950"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:58.088466"], ["updated_at", "2025-11-21 11:19:58.088466"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-21 11:19:58 +0000 Processing by BreakEscape::Api::GamesController#sync_state as HTML Parameters: {"currentRoom"=>"office", "id"=>"1"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.2ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"office\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:19:58.092689"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.5ms (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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:58.094646"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:58.093910"], ["updated_at", "2025-11-21 11:19:58.093910"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:19:58 +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.7ms | GC: 0.1ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.1ms) Completed 200 OK in 2ms (Views: 1.3ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:58.100420"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:58.099847"], ["updated_at", "2025-11-21 11:19:58.099847"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-21 11:19:58 +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.2ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:58.104054"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:58.103505"], ["updated_at", "2025-11-21 11:19:58.103505"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:19:58 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:58.107210"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:58.106712"], ["updated_at", "2025-11-21 11:19:58.106712"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:19:58 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:58.111316"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:58.110820"], ["updated_at", "2025-11-21 11:19:58.110820"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:19:58 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:19:58.115628"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:19:58.115079"], ["updated_at", "2025-11-21 11:19:58.115079"]] 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-21 11:19:58 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.0ms) rollback transaction ActiveRecord::InternalMetadata Load (0.2ms) 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-21 11:20:17', '2025-11-21 11:20:17'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:20:17', '2025-11-21 11:20:17'); 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-21 11:20:17', '2025-11-21 11:20:17'); 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-21 11:20:17', '2025-11-21 11:20:17')  (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_show_should_inject_game_configuration ---------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.270712"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.270074"], ["updated_at", "2025-11-21 11:20:17.270074"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:20:17 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"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::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.6ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.8ms | GC: 0.0ms) Completed 200 OK in 9ms (Views: 3.2ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ---------------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_bootstrap_endpoint_should_return_game_state ---------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.288287"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.287689"], ["updated_at", "2025-11-21 11:20:17.287689"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-21 11:20:17 +0000 Processing by BreakEscape::Api::GamesController#bootstrap 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]] Completed 200 OK in 1ms (Views: 0.1ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.292820"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.292279"], ["updated_at", "2025-11-21 11:20:17.292279"]] 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-21 11:20:17 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.296401"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.295792"], ["updated_at", "2025-11-21 11:20:17.295792"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:20:17 +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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.301093"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.300482"], ["updated_at", "2025-11-21 11:20:17.300482"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 11:20:17 +0000 Processing by BreakEscape::Api::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]] Completed 422 Unprocessable Content in 4ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 3.0ms) TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ---------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.309604"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.308871"], ["updated_at", "2025-11-21 11:20:17.308871"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-21 11:20:17 +0000 Processing by BreakEscape::Api::GamesController#sync_state as HTML Parameters: {"currentRoom"=>"office", "id"=>"1"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* 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]] BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"office\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:20:17.311950"], ["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_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.314416"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.313777"], ["updated_at", "2025-11-21 11:20:17.313777"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:20:17 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"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::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.3ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.4ms | GC: 0.0ms) Completed 200 OK in 2ms (Views: 0.6ms | ActiveRecord: 0.2ms (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.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.322580"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.321618"], ["updated_at", "2025-11-21 11:20:17.321618"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-21 11:20:17 +0000 Processing by BreakEscape::Api::GamesController#inventory as HTML Parameters: {"action_type"=>"add", "item"=>{"type"=>"key", "name"=>"Test Key", "id"=>"test_key"}, "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* 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]] 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\":\"key\",\"name\":\"Test Key\",\"id\":\"test_key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:20:17.326391"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 2ms (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::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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.329518"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.328492"], ["updated_at", "2025-11-21 11:20:17.328492"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:20:17 +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.1ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.334450"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.333778"], ["updated_at", "2025-11-21 11:20:17.333778"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-21 11:20:17 +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.3ms | ActiveRecord: 0.1ms (3 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.338084"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.337563"], ["updated_at", "2025-11-21 11:20:17.337563"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:20:17 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.341537"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.340970"], ["updated_at", "2025-11-21 11:20:17.340970"]] 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-21 11:20:17 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.344561"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.344062"], ["updated_at", "2025-11-21 11:20:17.344062"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:20:17 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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] Loading ink for NPC: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 3ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 2.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.356406"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.354362"], ["updated_at", "2025-11-21 11:20:17.354362"]] 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-21 11:20:17 +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.2ms) Completed 200 OK in 2ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 1.7ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.371289"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.369334"], ["updated_at", "2025-11-21 11:20:17.369334"]] 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-21 11:20:17 +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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.374991"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.374465"], ["updated_at", "2025-11-21 11:20:17.374465"]] 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-21 11:20:17 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.377835"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.377207"], ["updated_at", "2025-11-21 11:20:17.377207"]] 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-21 11:20:17 +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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.381837"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.381111"], ["updated_at", "2025-11-21 11:20:17.381111"]] 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-21 11:20:17 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.384883"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.384365"], ["updated_at", "2025-11-21 11:20:17.384365"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:20:17 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.388090"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.387519"], ["updated_at", "2025-11-21 11:20:17.387519"]] 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-21 11:20:17 +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:59: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.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------- BreakEscape::NPCInkLoadingTest: test_npc-manager_should_load_stories_via_API_endpoint ------------------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.531916"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.531347"], ["updated_at", "2025-11-21 11:20:17.531347"]] 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-21 11:20:17 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.535173"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.534647"], ["updated_at", "2025-11-21 11:20:17.534647"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:20:17 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.538835"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.538323"], ["updated_at", "2025-11-21 11:20:17.538323"]] 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-21 11:20:17 +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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:17.541834"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:17.541304"], ["updated_at", "2025-11-21 11:20:17.541304"]] 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-21 11:20:17 +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 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-21 11:20:34', '2025-11-21 11:20:34'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 11:20:34', '2025-11-21 11:20:34'); 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-21 11:20:34', '2025-11-21 11:20:34'); 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-21 11:20:34', '2025-11-21 11:20:34')  (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::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.1ms) INSERT INTO "break_escape_missions" ("name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["name", "test"], ["display_name", "Test"], ["description", nil], ["published", 0], ["difficulty_level", 1], ["created_at", "2025-11-21 11:20:34.828211"], ["updated_at", "2025-11-21 11:20:34.828211"]] 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.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::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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.840984"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.840270"], ["updated_at", "2025-11-21 11:20:34.840270"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.843273"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.842765"], ["updated_at", "2025-11-21 11:20:34.842765"]] 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-21 11:20:34.844280"], ["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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.846035"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.845329"], ["updated_at", "2025-11-21 11:20:34.845329"]] 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-21 11:20:34.847154"], ["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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.849011"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.848336"], ["updated_at", "2025-11-21 11:20:34.848336"]] 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-21 11:20:34.850026"], ["id", 1]] 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.851677"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.851133"], ["updated_at", "2025-11-21 11:20:34.851133"]] 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-21 11:20:34.852803"], ["id", 1]] 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-21 11:20:34 +0000 Processing by BreakEscape::MissionsController#index as HTML 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]] 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 Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] 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 4ms (Views: 1.9ms | ActiveRecord: 0.1ms (2 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::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-21 11:20:34 +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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.876994"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.876438"], ["updated_at", "2025-11-21 11:20:34.876438"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 3ms (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_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-21 11:20:34 +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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.880600"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.879978"], ["updated_at", "2025-11-21 11:20:34.879978"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 3ms (ActiveRecord: 0.3ms (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-21 11:20:34 +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 Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.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 (2 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-21 11:20:34 +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 Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.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.0ms (2 queries, 0 cached) | GC: 0.0ms) 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_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_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_WOFF_font_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_HTML_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_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_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_determines_WAV_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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.889701"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.889139"], ["updated_at", "2025-11-21 11:20:34.889139"]] 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-21 11:20:34 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"security_guard", "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: security_guard [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) Completed 404 Not Found in 2ms (Views: 0.1ms | 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-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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.898193"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.894482"], ["updated_at", "2025-11-21 11:20:34.894482"]] 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-21 11:20:34 +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.2ms) Completed 200 OK in 1ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.2ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.902414"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.901854"], ["updated_at", "2025-11-21 11:20:34.901854"]] 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-21 11:20:34 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.905400"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.904921"], ["updated_at", "2025-11-21 11:20:34.904921"]] 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-21 11:20:34 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.907978"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.907506"], ["updated_at", "2025-11-21 11:20:34.907506"]] 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-21 11:20:34 +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: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.911165"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.910674"], ["updated_at", "2025-11-21 11:20:34.910674"]] 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-21 11:20:34 +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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.914227"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.913525"], ["updated_at", "2025-11-21 11:20:34.913525"]] 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-21 11:20:34 +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_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.917507"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.916980"], ["updated_at", "2025-11-21 11:20:34.916980"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:20:34 +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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.920973"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.920366"], ["updated_at", "2025-11-21 11:20:34.920366"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:20:34 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.924151"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.923655"], ["updated_at", "2025-11-21 11:20:34.923655"]] 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-21 11:20:34 +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-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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.926647"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.926188"], ["updated_at", "2025-11-21 11:20:34.926188"]] 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-21 11:20:34 +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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:34.929415"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:34.928794"], ["updated_at", "2025-11-21 11:20:34.928794"]] 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-21 11:20:34 +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:59: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_404_for_NPC_without_story_file --------------------------------------------------------------------------------- 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\":\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:35.090913"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:35.090394"], ["updated_at", "2025-11-21 11:20:35.090394"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:20:35 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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_should_serve_sound_manager_module -------------------------------------------------------------------------------- Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-21 11:20:35 +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_CSS_files_should_be_accessible_from_main_game -------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 11:20:35 +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-21 11:20:35 +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_load_all_required_game_files_in_correct_order --------------------------------------------------------------------------------------------------- Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 11:20:35 +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_test_asset_page_loads_correctly ------------------------------------------------------------------------------ Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 11:20:35 +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_lockpicking_minigame -------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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_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-21 11:20:35 +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_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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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_game_core_with_asset_references ------------------------------------------------------------------------------------------- Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-21 11:20:35 +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-21 11:20:35 +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.3ms | 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-21 11:20:35 +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-21 11:20:35 +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_all_response_headers_are_correct ------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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_door_tile_image --------------------------------------------------------------------------- Started GET "/break_escape/assets/tiles/door.png" for 127.0.0.1 at 2025-11-21 11:20:35 +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 --------------------------------------------- BreakEscapeTest: test_it_has_a_version_number --------------------------------------------- TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ---------------------------------------------------------------------------------- BreakEscape::GamesControllerTest: test_bootstrap_endpoint_should_return_game_state ---------------------------------------------------------------------------------- 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\":\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:35.117178"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:35.116441"], ["updated_at", "2025-11-21 11:20:35.116441"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/bootstrap" for 127.0.0.1 at 2025-11-21 11:20:35 +0000 Processing by BreakEscape::Api::GamesController#bootstrap 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]] Completed 200 OK in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.1ms) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:35.122134"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:35.121528"], ["updated_at", "2025-11-21 11:20:35.121528"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 11:20:35 +0000 Processing by BreakEscape::Api::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]] 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:35.127199"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:35.126705"], ["updated_at", "2025-11-21 11:20:35.126705"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink?npc=test-npc" for 127.0.0.1 at 2025-11-21 11:20:35 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"test-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: test-npc [BreakEscape] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:35.130914"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:35.130351"], ["updated_at", "2025-11-21 11:20:35.130351"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-21 11:20:35 +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.2ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:35.135634"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:35.135001"], ["updated_at", "2025-11-21 11:20:35.135001"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:20:35 +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.6ms | 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:35.140353"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:35.139815"], ["updated_at", "2025-11-21 11:20:35.139815"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-21 11:20:35 +0000 Processing by BreakEscape::Api::GamesController#inventory as HTML Parameters: {"action_type"=>"add", "item"=>{"type"=>"key", "name"=>"Test Key", "id"=>"test_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]] 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\":\"key\",\"name\":\"Test Key\",\"id\":\"test_key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:20:35.142504"], ["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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:35.144361"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:35.143793"], ["updated_at", "2025-11-21 11:20:35.143793"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:20:35 +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::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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:35.148868"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:35.148222"], ["updated_at", "2025-11-21 11:20:35.148222"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-21 11:20:35 +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.1ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:35.152778"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:35.152251"], ["updated_at", "2025-11-21 11:20:35.152251"]] 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-21 11:20:35 +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] Available NPCs: neye_eve (reception), gossip_girl (reception), helper_npc (reception) 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:35.156144"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:35.155647"], ["updated_at", "2025-11-21 11:20:35.155647"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-21 11:20:35 +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 ---------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 11:20:35.159787"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 11:20:35.159312"], ["updated_at", "2025-11-21 11:20:35.159312"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-21 11:20:35 +0000 Processing by BreakEscape::Api::GamesController#sync_state as HTML Parameters: {"currentRoom"=>"office", "id"=>"1"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* 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]] BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"office\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 11:20:35.161923"], ["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::StaticFilesControllerTest: test_JS:_should_serve_nested_files -------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 11:20:35 +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_serve_test_files_with_correct_MIME_type ------------------------------------------------------------------------------------------------- Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-21 11:20:35 +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_Headers:_should_include_Content-Length ----------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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_return_404_for_non-existent_files --------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/sounds/non-existent.mp3" for 127.0.0.1 at 2025-11-21 11:20:35 +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_Security:_should_prevent_directory_traversal_in_assets --------------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/../../config/database.yml" for 127.0.0.1 at 2025-11-21 11:20:35 +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-21 11:20:35 +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_Minigame:_should_serve_lockpicking_script -------------------------------------------------------------------------------------- Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-21 11:20:35 +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_JS:_should_return_404_for_non-existent_files ----------------------------------------------------------------------------------------- Started GET "/break_escape/js/non-existent.js" for 127.0.0.1 at 2025-11-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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_Integrity:_image_files_are_non-empty --------------------------------------------------------------------------------- Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 11:20:35 +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.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-21 11:20:35 +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-21 11:20:35 +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_handle_files_with_multiple_dots ------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/tiles/door_sheet_32.png" for 127.0.0.1 at 2025-11-21 11:20:35 +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_files_with_correct_MIME_type ------------------------------------------------------------------------------------------ Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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_Security:_should_prevent_directory_traversal_in_CSS ------------------------------------------------------------------------------------------------ Started GET "/break_escape/css/../../config/database.yml" for 127.0.0.1 at 2025-11-21 11:20:35 +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_Security:_should_prevent_directory_traversal_in_JS ----------------------------------------------------------------------------------------------- Started GET "/break_escape/js/../../config/secrets.yml" for 127.0.0.1 at 2025-11-21 11:20:35 +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.1ms) 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-21 11:20:35 +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:_constants_define_GAME_CONFIG_with_baseURL ---------------------------------------------------------------------------------------------- Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-21 11:20:35 +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_PNG_tiles_with_correct_MIME_type -------------------------------------------------------------------------------------------------- Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-21 11:20:35 +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-21 11:20:35 +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-21 11:20:35 +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_set_Content-Disposition_to_inline ---------------------------------------------------------------------------------------------- Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-21 11:20:35 +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-21 11:20:35 +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 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-21 12:10:53', '2025-11-21 12:10:53'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 12:10:53', '2025-11-21 12:10:53'); 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-21 12:10:53', '2025-11-21 12:10:53'); 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-21 12:10:53', '2025-11-21 12:10:53')  (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::RoomLazyLoadTest: test_should_return_room_data_for_valid_room_id ----------------------------------------------------------------------------- TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------ BreakEscape::RoomLazyLoadTest: test_room_response_includes_all_room_data ------------------------------------------------------------------------ TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::RoomLazyLoadTest: test_should_return_400_when_room_id_is_missing ----------------------------------------------------------------------------- TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction --------------------------------------------------------------------------- BreakEscape::RoomLazyLoadTest: test_should_return_404_for_non-existent_room --------------------------------------------------------------------------- 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-21 12:11:18', '2025-11-21 12:11:18'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 12:11:18', '2025-11-21 12:11: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-21 12:11:18', '2025-11-21 12:11: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-21 12:11:18', '2025-11-21 12:11:18')  (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::RoomLazyLoadTest: test_should_return_room_data_for_valid_room_id ----------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:11:18.699770"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:11:18.698981"], ["updated_at", "2025-11-21 12:11:18.698981"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:11:18.703377"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:11:18.702814"], ["updated_at", "2025-11-21 12:11:18.702814"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:11:18.706168"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:11:18.705623"], ["updated_at", "2025-11-21 12:11:18.705623"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:11:18.708965"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:11:18.708354"], ["updated_at", "2025-11-21 12:11:18.708354"]] 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-21 12:11:50', '2025-11-21 12:11:50'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 12:11:50', '2025-11-21 12:11:50'); 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-21 12:11:50', '2025-11-21 12:11:50'); 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-21 12:11:50', '2025-11-21 12:11:50')  (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::RoomLazyLoadTest: test_should_return_404_for_non-existent_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:11:50.749782"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:11:50.748964"], ["updated_at", "2025-11-21 12:11:50.748964"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/games/1/room/non_existent_room" for 127.0.0.1 at 2025-11-21 12:11:50 +0000 ActionController::RoutingError (No route matches [GET] "/games/1/room/non_existent_room"): 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:11:50.801781"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:11:50.801143"], ["updated_at", "2025-11-21 12:11:50.801143"]] 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:11:50.804190"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:11:50.803622"], ["updated_at", "2025-11-21 12:11:50.803622"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/games/1/room/reception" for 127.0.0.1 at 2025-11-21 12:11:50 +0000 ActionController::RoutingError (No route matches [GET] "/games/1/room/reception"): 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:11:50.845568"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:11:50.845050"], ["updated_at", "2025-11-21 12:11:50.845050"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/games/1/room/reception" for 127.0.0.1 at 2025-11-21 12:11:50 +0000 ActionController::RoutingError (No route matches [GET] "/games/1/room/reception"): 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-21 12:12:39', '2025-11-21 12:12:39'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 12:12:39', '2025-11-21 12:12: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-21 12:12:39', '2025-11-21 12:12: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-21 12:12:39', '2025-11-21 12:12:39')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.7ms) commit transaction  (0.0ms) PRAGMA foreign_key_check TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::RoomLazyLoadTest: test_should_return_room_data_for_valid_room_id ----------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:12:39.234541"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:12:39.233871"], ["updated_at", "2025-11-21 12:12:39.233871"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/games/1/room/reception" for 127.0.0.1 at 2025-11-21 12:12:39 +0000 ActionController::RoutingError (No route matches [GET] "/games/1/room/reception"): 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-21 12:13:08', '2025-11-21 12:13:08'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 12:13:08', '2025-11-21 12:13: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-21 12:13:08', '2025-11-21 12:13: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-21 12:13:08', '2025-11-21 12:13:08')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (1.7ms) commit transaction  (0.0ms) PRAGMA foreign_key_check TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::RoomLazyLoadTest: test_should_return_400_when_room_id_is_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:13:08.248311"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:13:08.247648"], ["updated_at", "2025-11-21 12:13:08.247648"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:13:08.251234"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:13:08.250701"], ["updated_at", "2025-11-21 12:13:08.250701"]] 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-21 12:13:08 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"non_existent_room"} 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]] Completed 500 Internal Server Error in 2ms (ActiveRecord: 0.1ms (2 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:13:08.261835"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:13:08.261259"], ["updated_at", "2025-11-21 12:13:08.261259"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 12:13:08 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] Completed 500 Internal Server Error in 1ms (ActiveRecord: 0.0ms (2 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:13:08.266675"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:13:08.266104"], ["updated_at", "2025-11-21 12:13:08.266104"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 12:13:08 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] Completed 500 Internal Server Error in 1ms (ActiveRecord: 0.1ms (2 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-21 12:13:27', '2025-11-21 12:13:27'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 12:13:27', '2025-11-21 12:13:27'); 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-21 12:13:27', '2025-11-21 12:13:27'); 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-21 12:13:27', '2025-11-21 12:13:27')  (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::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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:13:27.421742"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:13:27.421132"], ["updated_at", "2025-11-21 12:13:27.421132"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 12:13:27 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} 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] Serving room data for: reception Completed 200 OK in 3ms (Views: 0.2ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.2ms) 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:13:27.433599"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:13:27.432980"], ["updated_at", "2025-11-21 12:13:27.432980"]] 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-21 12:13:27 +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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:13:27.437214"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:13:27.436695"], ["updated_at", "2025-11-21 12:13:27.436695"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 12:13:27 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (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: reception 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:13:27.440579"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:13:27.440072"], ["updated_at", "2025-11-21 12:13:27.440072"]] 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 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 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-21 12:22:40', '2025-11-21 12:22:40'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 12:22:40', '2025-11-21 12:22:40'); 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-21 12:22:40', '2025-11-21 12:22:40'); 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-21 12:22:40', '2025-11-21 12:22:40')  (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::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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:22:40.607249"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:22:40.606553"], ["updated_at", "2025-11-21 12:22:40.606553"]] 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\":\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:22:40.610017"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:22:40.609429"], ["updated_at", "2025-11-21 12:22:40.609429"]] 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.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\":\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:22:40.612614"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:22:40.611992"], ["updated_at", "2025-11-21 12:22:40.611992"]] 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\":\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:22:40.615271"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:22:40.614660"], ["updated_at", "2025-11-21 12:22:40.614660"]] 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\":\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:22:40.619597"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:22:40.619055"], ["updated_at", "2025-11-21 12:22:40.619055"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::FilteredScenarioTest: test_scenario_endpoint_returns_filtered_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:22:40.621948"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:22:40.621435"], ["updated_at", "2025-11-21 12:22:40.621435"]] 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-21 12:22:54', '2025-11-21 12:22:54'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 12:22:54', '2025-11-21 12:22: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-21 12:22:54', '2025-11-21 12:22: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-21 12:22:54', '2025-11-21 12:22:54')  (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::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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:22:54.937299"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:22:54.936650"], ["updated_at", "2025-11-21 12:22:54.936650"]] 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:22:54.940455"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:22:54.939886"], ["updated_at", "2025-11-21 12:22:54.939886"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::FilteredScenarioTest: test_scenario_endpoint_returns_filtered_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:22:54.943072"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:22:54.942526"], ["updated_at", "2025-11-21 12:22:54.942526"]] 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:22:54.945648"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:22:54.945077"], ["updated_at", "2025-11-21 12:22:54.945077"]] 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:22:54.951292"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:22:54.950616"], ["updated_at", "2025-11-21 12:22:54.950616"]] 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:22:54.956649"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:22:54.955897"], ["updated_at", "2025-11-21 12:22:54.955897"]] 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-21 12:23:23', '2025-11-21 12:23:23'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 12:23:23', '2025-11-21 12:23:23'); 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-21 12:23:23', '2025-11-21 12:23:23'); 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-21 12:23:23', '2025-11-21 12:23:23')  (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::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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:23:23.214710"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:23:23.214041"], ["updated_at", "2025-11-21 12:23:23.214041"]] 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:23:23.217681"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:23:23.217129"], ["updated_at", "2025-11-21 12:23:23.217129"]] 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:23:23.222933"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:23:23.222086"], ["updated_at", "2025-11-21 12:23:23.222086"]] 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:23:23.226305"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:23:23.225464"], ["updated_at", "2025-11-21 12:23:23.225464"]] 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:23:23.232278"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:23:23.229085"], ["updated_at", "2025-11-21 12:23:23.229085"]] 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-21 12:23:27', '2025-11-21 12:23:27'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 12:23:27', '2025-11-21 12:23:27'); 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-21 12:23:27', '2025-11-21 12:23:27'); 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-21 12:23:27', '2025-11-21 12:23:27')  (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::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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 12:23:27.667504"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 12:23:27.666827"], ["updated_at", "2025-11-21 12:23:27.666827"]] 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-21 13:37:35', '2025-11-21 13:37:35'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 13:37:35', '2025-11-21 13:37:35'); 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-21 13:37:35', '2025-11-21 13:37:35'); 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-21 13:37:35', '2025-11-21 13:37:35')  (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::RoomLazyLoadTest: test_should_return_400_when_room_id_is_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:37:35.085632"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:37:35.084876"], ["updated_at", "2025-11-21 13:37:35.084876"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:37:35.088422"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:37:35.087903"], ["updated_at", "2025-11-21 13:37:35.087903"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 13:37:35 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} 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] Serving room data for: reception Completed 200 OK in 4ms (Views: 0.2ms | ActiveRecord: 0.2ms (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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:37:35.100536"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:37:35.099997"], ["updated_at", "2025-11-21 13:37:35.099997"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 13:37:35 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (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: reception 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:37:35.104130"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:37:35.103584"], ["updated_at", "2025-11-21 13:37:35.103584"]] 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-21 13:37:35 +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 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-21 13:37:44', '2025-11-21 13:37:44'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 13:37:44', '2025-11-21 13:37:44'); 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-21 13:37:44', '2025-11-21 13:37:44'); 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-21 13:37:44', '2025-11-21 13:37:44')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (1.8ms) commit transaction  (0.0ms) PRAGMA foreign_key_check TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::RoomLazyLoadTest: test_should_return_400_when_room_id_is_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:37:44.034562"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:37:44.033806"], ["updated_at", "2025-11-21 13:37:44.033806"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:37:44.037328"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:37:44.036806"], ["updated_at", "2025-11-21 13:37:44.036806"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 13:37:44 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} 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] Serving room data for: reception Completed 200 OK in 4ms (Views: 0.2ms | ActiveRecord: 0.2ms (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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:37:44.049557"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:37:44.048991"], ["updated_at", "2025-11-21 13:37:44.048991"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 13:37:44 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (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: reception 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:37:44.053293"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:37:44.052761"], ["updated_at", "2025-11-21 13:37:44.052761"]] 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-21 13:37:44 +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 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-21 13:44:41', '2025-11-21 13:44:41'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 13:44:41', '2025-11-21 13:44:41'); 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-21 13:44:41', '2025-11-21 13:44:41'); 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-21 13:44:41', '2025-11-21 13:44:41')  (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::RoomLazyLoadTest: test_should_return_404_for_non-existent_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:44:41.134472"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:44:41.133747"], ["updated_at", "2025-11-21 13:44:41.133747"]] 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-21 13:44:41 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"non_existent_room"} 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]] Completed 404 Not Found in 4ms (Views: 0.1ms | ActiveRecord: 0.2ms (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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:44:41.147032"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:44:41.146458"], ["updated_at", "2025-11-21 13:44:41.146458"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 13:44:41 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (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: reception 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:44:41.150685"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:44:41.150174"], ["updated_at", "2025-11-21 13:44:41.150174"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:44:41.152823"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:44:41.152284"], ["updated_at", "2025-11-21 13:44:41.152284"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 13:44:41 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (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: reception Completed 200 OK in 1ms (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-21 13:45:07', '2025-11-21 13:45:07'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 13:45:07', '2025-11-21 13:45:07'); 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-21 13:45:07', '2025-11-21 13:45:07'); 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-21 13:45:07', '2025-11-21 13:45:07')  (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::RoomLazyLoadTest: test_should_return_room_data_for_valid_room_id ----------------------------------------------------------------------------- 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:07.206972"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:07.206316"], ["updated_at", "2025-11-21 13:45:07.206316"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 13:45:07 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} 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] Serving room data for: reception Completed 200 OK in 3ms (Views: 0.2ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::RoomLazyLoadTest: test_room_response_includes_objects_array_when_present_in_scenario ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:07.218888"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:07.218354"], ["updated_at", "2025-11-21 13:45:07.218354"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:07.220405"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:07.219916"], ["updated_at", "2025-11-21 13:45:07.219916"]] TRANSACTION (0.0ms) ROLLBACK TO SAVEPOINT active_record_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:07.222814"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:07.222245"], ["updated_at", "2025-11-21 13:45:07.222245"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:07.225431"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:07.224869"], ["updated_at", "2025-11-21 13:45:07.224869"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 13:45:07 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (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: reception Completed 200 OK in 1ms (Views: 0.2ms | 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:07.229627"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:07.229056"], ["updated_at", "2025-11-21 13:45:07.229056"]] 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-21 13:45:07 +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.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-21 13:45:21', '2025-11-21 13:45:21'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 13:45:21', '2025-11-21 13:45:21'); 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-21 13:45:21', '2025-11-21 13:45:21'); 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-21 13:45:21', '2025-11-21 13:45:21')  (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::RoomLazyLoadTest: test_should_return_404_for_non-existent_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:21.542657"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:21.541869"], ["updated_at", "2025-11-21 13:45:21.541869"]] 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-21 13:45:21 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"non_existent_room"} 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]] Completed 404 Not Found in 3ms (Views: 0.1ms | ActiveRecord: 0.2ms (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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:21.554682"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:21.554132"], ["updated_at", "2025-11-21 13:45:21.554132"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::RoomLazyLoadTest: test_room_response_includes_objects_array_when_present_in_scenario ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:21.556910"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:21.556338"], ["updated_at", "2025-11-21 13:45:21.556338"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:21.559401"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:21.558879"], ["updated_at", "2025-11-21 13:45:21.558879"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 13:45:21 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (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: reception 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:21.563407"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:21.562841"], ["updated_at", "2025-11-21 13:45:21.562841"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 13:45:21 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (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: reception Completed 200 OK in 1ms (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-21 13:45:33', '2025-11-21 13:45:33'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 13:45:33', '2025-11-21 13:45:33'); 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-21 13:45:33', '2025-11-21 13:45:33'); 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-21 13:45:33', '2025-11-21 13:45:33')  (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::RoomLazyLoadTest: test_should_return_404_for_non-existent_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:33.114782"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:33.114022"], ["updated_at", "2025-11-21 13:45:33.114022"]] 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-21 13:45:33 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"non_existent_room"} 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]] Completed 404 Not Found in 3ms (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_room_response_includes_objects_array_when_present_in_scenario ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:33.126565"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:33.125999"], ["updated_at", "2025-11-21 13:45:33.125999"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:33.129191"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:33.128595"], ["updated_at", "2025-11-21 13:45:33.128595"]] 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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:33.131589"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:33.131006"], ["updated_at", "2025-11-21 13:45:33.131006"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 13:45:33 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (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: reception 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_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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:33.135362"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:33.134815"], ["updated_at", "2025-11-21 13:45:33.134815"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 13:45:33 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (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: reception Completed 200 OK in 1ms (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 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-21 13:45:50', '2025-11-21 13:45:50'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 13:45:50', '2025-11-21 13:45:50'); 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-21 13:45:50', '2025-11-21 13:45:50'); 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-21 13:45:50', '2025-11-21 13:45:50')  (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::RoomLazyLoadTest: test_should_return_400_when_room_id_is_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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:50.087465"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:50.086644"], ["updated_at", "2025-11-21 13:45:50.086644"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:50.090977"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:50.090369"], ["updated_at", "2025-11-21 13:45:50.090369"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 13:45:50 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} 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] Serving room data for: reception Completed 200 OK in 4ms (Views: 0.2ms | ActiveRecord: 0.2ms (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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:50.103833"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:50.103277"], ["updated_at", "2025-11-21 13:45:50.103277"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/room/reception" for 127.0.0.1 at 2025-11-21 13:45:50 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"reception"} BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (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: reception 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.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "\"{\\\"currentRoom\\\":null,\\\"unlockedRooms\\\":[],\\\"unlockedObjects\\\":[],\\\"inventory\\\":[],\\\"encounteredNPCs\\\":[],\\\"globalVariables\\\":{},\\\"biometricSamples\\\":[],\\\"biometricUnlocks\\\":[],\\\"bluetoothDevices\\\":[],\\\"notes\\\":[],\\\"health\\\":100}\""], ["status", "in_progress"], ["started_at", "2025-11-21 13:45:50.107989"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 13:45:50.107377"], ["updated_at", "2025-11-21 13:45:50.107377"]] 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-21 13:45:50 +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.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.0ms) rollback transaction ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.4ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.3ms) PRAGMA foreign_keys  (0.0ms) PRAGMA defer_foreign_keys  (0.1ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-21 19:44:07', '2025-11-21 19:44:07'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 19:44:07', '2025-11-21 19:44:07'); 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-21 19:44:07', '2025-11-21 19:44:07'); 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-21 19:44:07', '2025-11-21 19:44:07')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (5.5ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.558038"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.555420"], ["updated_at", "2025-11-21 19:44:07.555420"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=0000, method=pin [BreakEscape] Object not found: safe_pin Completed 422 Unprocessable Content in 31ms (Views: 0.2ms | ActiveRecord: 0.4ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.694684"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.692706"], ["updated_at", "2025-11-21 19:44:07.692706"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Object not found: chest_unlocked Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation ----------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.706087"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.704374"], ["updated_at", "2025-11-21 19:44:07.704374"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.715517"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.713859"], ["updated_at", "2025-11-21 19:44:07.713859"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_key, attempt=, method=key Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.724555"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.722769"], ["updated_at", "2025-11-21 19:44:07.722769"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=0000, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.734804"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.732988"], ["updated_at", "2025-11-21 19:44:07.732988"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=wrongpassword, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.755149"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.752995"], ["updated_at", "2025-11-21 19:44:07.752995"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=, method=password [BreakEscape] Object not found: cabinet_password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) 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.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.765299"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.763320"], ["updated_at", "2025-11-21 19:44:07.763320"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=scanner_biometric, attempt=, method=biometric [BreakEscape] Object not found: scanner_biometric Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.775797"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.774009"], ["updated_at", "2025-11-21 19:44:07.774009"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.785427"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.783332"], ["updated_at", "2025-11-21 19:44:07.783332"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"invalid_method", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=invalid_method Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.796770"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.792231"], ["updated_at", "2025-11-21 19:44:07.792231"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=box_lockpick, attempt=, method=lockpick [BreakEscape] Object not found: box_lockpick Completed 422 Unprocessable Content in 4ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.820356"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.814519"], ["updated_at", "2025-11-21 19:44:07.814519"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=door_rfid, attempt=, method=rfid [BreakEscape] Object not found: door_rfid Completed 422 Unprocessable Content in 5ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly ------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (1.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.850177"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.841812"], ["updated_at", "2025-11-21 19:44:07.841812"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents -------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.864614"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.862294"], ["updated_at", "2025-11-21 19:44:07.862294"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Object not found: safe_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.8ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.873513"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.871784"], ["updated_at", "2025-11-21 19:44:07.871784"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=secret123, method=password [BreakEscape] Object not found: cabinet_password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks ----------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.883747"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.881978"], ["updated_at", "2025-11-21 19:44:07.881978"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.893150"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.891536"], ["updated_at", "2025-11-21 19:44:07.891536"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=drawer_key, attempt=, method=key [BreakEscape] Object not found: drawer_key Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity ----------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.902153"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.900548"], ["updated_at", "2025-11-21 19:44:07.900548"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=OpenSesame, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.915528"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.908396"], ["updated_at", "2025-11-21 19:44:07.908396"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Object not found: safe_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.924092"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.922504"], ["updated_at", "2025-11-21 19:44:07.922504"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.933228"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.931102"], ["updated_at", "2025-11-21 19:44:07.931102"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"non_existent_object", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=non_existent_object, attempt=1234, method=pin [BreakEscape] Object not found: non_existent_object Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.943466"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.941806"], ["updated_at", "2025-11-21 19:44:07.941806"]] TRANSACTION (0.3ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=terminal_bluetooth, attempt=, method=bluetooth [BreakEscape] Object not found: terminal_bluetooth Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail ------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.8ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.953587"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.951648"], ["updated_at", "2025-11-21 19:44:07.951648"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"non_existent_room", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=non_existent_room, attempt=1234, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:44:07.963235"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:44:07.961490"], ["updated_at", "2025-11-21 19:44:07.961490"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:44:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "environment"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC ActiveRecord::InternalMetadata Load (0.4ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-21 19:46:06', '2025-11-21 19:46:06'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 19:46:06', '2025-11-21 19:46:06'); 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-21 19:46:06', '2025-11-21 19:46:06'); 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-21 19:46:06', '2025-11-21 19:46:06')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (3.9ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) 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.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.130624"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.128036"], ["updated_at", "2025-11-21 19:46:07.128036"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=terminal_bluetooth, attempt=, method=bluetooth [BreakEscape] Object not found: terminal_bluetooth Completed 422 Unprocessable Content in 30ms (Views: 0.3ms | ActiveRecord: 0.4ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail ------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.262298"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.260628"], ["updated_at", "2025-11-21 19:46:07.260628"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"non_existent_room", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=non_existent_room, attempt=1234, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation ----------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.272207"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.270541"], ["updated_at", "2025-11-21 19:46:07.270541"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks ----------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.281027"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.279373"], ["updated_at", "2025-11-21 19:46:07.279373"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.289580"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.287926"], ["updated_at", "2025-11-21 19:46:07.287926"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"invalid_method", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=invalid_method Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity ----------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.297890"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.296162"], ["updated_at", "2025-11-21 19:46:07.296162"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=OpenSesame, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.318180"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.304624"], ["updated_at", "2025-11-21 19:46:07.304624"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.327630"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.326029"], ["updated_at", "2025-11-21 19:46:07.326029"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=wrongpassword, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents -------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.336269"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.334670"], ["updated_at", "2025-11-21 19:46:07.334670"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Object not found: safe_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.345989"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.344029"], ["updated_at", "2025-11-21 19:46:07.344029"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=, method=password [BreakEscape] Object not found: cabinet_password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.354557"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.352722"], ["updated_at", "2025-11-21 19:46:07.352722"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=scanner_biometric, attempt=, method=biometric [BreakEscape] Object not found: scanner_biometric Completed 422 Unprocessable Content in 5ms (Views: 1.2ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.378481"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.371623"], ["updated_at", "2025-11-21 19:46:07.371623"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Object not found: chest_unlocked Completed 422 Unprocessable Content in 6ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.410964"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.402415"], ["updated_at", "2025-11-21 19:46:07.402415"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=0000, method=pin [BreakEscape] Object not found: safe_pin Completed 422 Unprocessable Content in 5ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.431835"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.429488"], ["updated_at", "2025-11-21 19:46:07.429488"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=drawer_key, attempt=, method=key [BreakEscape] Object not found: drawer_key Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.441637"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.439723"], ["updated_at", "2025-11-21 19:46:07.439723"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly ------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.450298"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.448561"], ["updated_at", "2025-11-21 19:46:07.448561"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.459098"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.457088"], ["updated_at", "2025-11-21 19:46:07.457088"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_key, attempt=, method=key Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.467286"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.465832"], ["updated_at", "2025-11-21 19:46:07.465832"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"non_existent_object", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=non_existent_object, attempt=1234, method=pin [BreakEscape] Object not found: non_existent_object Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.475091"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.473509"], ["updated_at", "2025-11-21 19:46:07.473509"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=door_rfid, attempt=, method=rfid [BreakEscape] Object not found: door_rfid Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.490222"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.487948"], ["updated_at", "2025-11-21 19:46:07.487948"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=0000, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.498955"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.497429"], ["updated_at", "2025-11-21 19:46:07.497429"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Object not found: safe_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.507804"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.505964"], ["updated_at", "2025-11-21 19:46:07.505964"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.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", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.516208"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.514555"], ["updated_at", "2025-11-21 19:46:07.514555"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=box_lockpick, attempt=, method=lockpick [BreakEscape] Object not found: box_lockpick Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:07.524829"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:07.523056"], ["updated_at", "2025-11-21 19:46:07.523056"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=secret123, method=password [BreakEscape] Object not found: cabinet_password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (1.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.4ms) PRAGMA foreign_keys  (0.1ms) PRAGMA defer_foreign_keys  (0.0ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-21 19:46:36', '2025-11-21 19:46:36'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 19:46:36', '2025-11-21 19:46:36'); 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-21 19:46:36', '2025-11-21 19:46:36'); 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-21 19:46:36', '2025-11-21 19:46:36')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.4ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:46:36.475950"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:46:36.472588"], ["updated_at", "2025-11-21 19:46:36.472588"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:46:36 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin Completed 422 Unprocessable Content in 34ms (Views: 0.3ms | ActiveRecord: 0.5ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.2ms) begin transaction  (0.6ms) PRAGMA foreign_keys  (0.0ms) PRAGMA defer_foreign_keys  (0.1ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-21 19:47:14', '2025-11-21 19:47:14'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 19:47:14', '2025-11-21 19:47: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-21 19:47:14', '2025-11-21 19:47: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-21 19:47:14', '2025-11-21 19:47:14')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.4ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_debug:_check_scenario_data_structure ------------------------------------------------------------------------ BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) 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.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "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\",\"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\":[100,0,100,0],\"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\":[100,0,100,0],\"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\":[0,50,100,150],\"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\":[0,50,100,150],\"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\":[50,25,0,75],\"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\":[68,10,48,30],\"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\":[68,10,48,30],\"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\":[50,25,0,75],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"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-21 19:47:15.226400"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:47:15.223476"], ["updated_at", "2025-11-21 19:47:15.223476"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-21 19:48:17', '2025-11-21 19:48:17'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 19:48:17', '2025-11-21 19:48:17'); 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-21 19:48:17', '2025-11-21 19:48:17'); 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-21 19:48:17', '2025-11-21 19:48:17')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (3.2ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_debug:_check_scenario_data_structure ------------------------------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:17.996962"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:17.996200"], ["updated_at", "2025-11-21 19:48:17.996200"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-21 19:48:54', '2025-11-21 19:48:54'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 19:48:54', '2025-11-21 19:48: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-21 19:48:54', '2025-11-21 19:48: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-21 19:48:54', '2025-11-21 19:48:54')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.6ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.205290"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.203739"], ["updated_at", "2025-11-21 19:48:55.203739"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} BreakEscape::Game Load (0.3ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=door_rfid, attempt=, method=rfid [BreakEscape] Found object: id=door_rfid, name=RFID Door, locked=true, requires=admin_badge TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"door_rfid\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.314023"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 36ms (Views: 0.3ms | ActiveRecord: 1.0ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.2ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.342265"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.342056"], ["updated_at", "2025-11-21 19:48:55.342056"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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-21 19:48:55.350782"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.350512"], ["updated_at", "2025-11-21 19:48:55.350512"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"invalid_method", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=invalid_method Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.358773"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.358572"], ["updated_at", "2025-11-21 19:48:55.358572"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=wrongpassword, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.8ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.367573"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.367346"], ["updated_at", "2025-11-21 19:48:55.367346"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=terminal_bluetooth, attempt=, method=bluetooth [BreakEscape] Found object: id=terminal_bluetooth, name=Bluetooth Terminal, locked=true, requires=admin_device TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.5ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"terminal_bluetooth\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.374097"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly ------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.378378"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.378205"], ["updated_at", "2025-11-21 19:48:55.378205"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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-21 19:48:55.383925"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 20ms (Views: 0.2ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 10.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.408526"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.415555"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.421649"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.421388"], ["updated_at", "2025-11-21 19:48:55.421388"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=scanner_biometric, attempt=, method=biometric [BreakEscape] Found object: id=scanner_biometric, name=Biometric Scanner, locked=true, requires=ceo_fingerprint TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"scanner_biometric\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.427049"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.431751"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.431543"], ["updated_at", "2025-11-21 19:48:55.431543"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"non_existent_object", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=non_existent_object, attempt=1234, method=pin [BreakEscape] Object not found: non_existent_object Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.438839"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.438635"], ["updated_at", "2025-11-21 19:48:55.438635"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=box_lockpick, attempt=, method=lockpick [BreakEscape] Found object: id=box_lockpick, name=Lockpickable Box, locked=true, requires= TRANSACTION (0.3ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) 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-21 19:48:55.443877"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 1.1ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.448007"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.447830"], ["updated_at", "2025-11-21 19:48:55.447830"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=0000, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.455453"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.455278"], ["updated_at", "2025-11-21 19:48:55.455278"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.460385"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.464861"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.464657"], ["updated_at", "2025-11-21 19:48:55.464657"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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-21 19:48:55.480052"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 14ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 10.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.3ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (4 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.491473"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.491204"], ["updated_at", "2025-11-21 19:48:55.491204"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.498218"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail ------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.503676"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.503486"], ["updated_at", "2025-11-21 19:48:55.503486"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"non_existent_room", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=non_existent_room, attempt=1234, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.510874"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.510677"], ["updated_at", "2025-11-21 19:48:55.510677"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"chest_unlocked\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.516494"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents -------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.521221"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.521010"], ["updated_at", "2025-11-21 19:48:55.521010"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.526625"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.530508"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.530336"], ["updated_at", "2025-11-21 19:48:55.530336"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=secret123, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='secret123', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"cabinet_password\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.535940"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.540909"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.540636"], ["updated_at", "2025-11-21 19:48:55.540636"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=0000, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='0000', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity ----------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.555094"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.554915"], ["updated_at", "2025-11-21 19:48:55.554915"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=OpenSesame, method=password Completed 422 Unprocessable Content in 3ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.563123"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.562911"], ["updated_at", "2025-11-21 19:48:55.562911"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_key, attempt=, method=key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.567497"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.572156"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.571979"], ["updated_at", "2025-11-21 19:48:55.571979"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.577121"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.581808"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.581600"], ["updated_at", "2025-11-21 19:48:55.581600"]] TRANSACTION (0.2ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=drawer_key, attempt=, method=key [BreakEscape] Found object: id=drawer_key, name=Locked Drawer, locked=true, requires=drawer_key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"drawer_key\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.589091"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks ----------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.594445"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.594098"], ["updated_at", "2025-11-21 19:48:55.594098"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.600361"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation ----------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 19:48:55.604476"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 19:48:55.604304"], ["updated_at", "2025-11-21 19:48:55.604304"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 19:48:55 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (1.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 19:48:55.610610"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 1.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.4ms) PRAGMA foreign_keys  (0.0ms) PRAGMA defer_foreign_keys  (0.1ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-21 21:05:20', '2025-11-21 21:05:20'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 21:05:20', '2025-11-21 21:05:20'); 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-21 21:05:20', '2025-11-21 21:05:20'); 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-21 21:05:20', '2025-11-21 21:05:20')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.6ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' --------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:20.856877"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:20.856088"], ["updated_at", "2025-11-21 21:05:20.856088"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:20 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=, method=unlocked [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door office_pin Completed 422 Unprocessable Content in 32ms (Views: 0.3ms | ActiveRecord: 0.4ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:20.988692"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:20.988503"], ["updated_at", "2025-11-21 21:05:20.988503"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:20 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"chest_unlocked\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:20.994499"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors ------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:20.999929"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:20.999696"], ["updated_at", "2025-11-21 21:05:20.999696"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:21.005009"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' -------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:21.008634"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:21.008454"], ["updated_at", "2025-11-21 21:05:21.008454"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=, method=unlocked [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED object safe_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.5ms) PRAGMA foreign_keys  (0.1ms) PRAGMA defer_foreign_keys  (0.1ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.3ms) 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-21 21:05:48', '2025-11-21 21:05:48'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 21:05:48', '2025-11-21 21:05:48'); 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-21 21:05:48', '2025-11-21 21:05:48'); 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-21 21:05:48', '2025-11-21 21:05:48')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.1ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks ----------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.350704"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.349916"], ["updated_at", "2025-11-21 21:05:48.349916"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "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.2ms) SELECT "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_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.463864"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 37ms (Views: 0.3ms | ActiveRecord: 1.1ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.490118"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.489896"], ["updated_at", "2025-11-21 21:05:48.489896"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=door_rfid, attempt=, method=rfid [BreakEscape] Found object: id=door_rfid, name=RFID Door, locked=true, requires=admin_badge TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"door_rfid\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.496762"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' -------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.501227"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.501054"], ["updated_at", "2025-11-21 21:05:48.501054"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=, method=unlocked [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED object safe_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly ------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.509840"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.509648"], ["updated_at", "2025-11-21 21:05:48.509648"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.515203"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.520595"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.525639"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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-21 21:05:48.530599"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.530348"], ["updated_at", "2025-11-21 21:05:48.530348"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=secret123, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='secret123', result=true TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"cabinet_password\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.536291"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.540848"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.540664"], ["updated_at", "2025-11-21 21:05:48.540664"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] 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-21 21:05:48.558901"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.8ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.564517"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.564326"], ["updated_at", "2025-11-21 21:05:48.564326"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=box_lockpick, attempt=, method=lockpick [BreakEscape] Found object: id=box_lockpick, name=Lockpickable Box, locked=true, requires= TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"box_lockpick\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.569661"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.573161"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.572995"], ["updated_at", "2025-11-21 21:05:48.572995"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"invalid_method", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=invalid_method Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity ----------------------------------------------------------------------------- BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.580496"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.580198"], ["updated_at", "2025-11-21 21:05:48.580198"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=OpenSesame, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.588766"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.588600"], ["updated_at", "2025-11-21 21:05:48.588600"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=scanner_biometric, attempt=, method=biometric [BreakEscape] Found object: id=scanner_biometric, name=Biometric Scanner, locked=true, requires=ceo_fingerprint TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.5ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"scanner_biometric\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.594411"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents -------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.598567"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.598378"], ["updated_at", "2025-11-21 21:05:48.598378"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.603610"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.606821"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.606659"], ["updated_at", "2025-11-21 21:05:48.606659"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=0000, method=pin Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.613218"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.613039"], ["updated_at", "2025-11-21 21:05:48.613039"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"chest_unlocked\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.617497"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.632162"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.621746"], ["updated_at", "2025-11-21 21:05:48.621746"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=drawer_key, attempt=, method=key [BreakEscape] Found object: id=drawer_key, name=Locked Drawer, locked=true, requires=drawer_key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.6ms) 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-21 21:05:48.637665"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.641870"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.641712"], ["updated_at", "2025-11-21 21:05:48.641712"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.648004"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.647818"], ["updated_at", "2025-11-21 21:05:48.647818"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"non_existent_object", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=non_existent_object, attempt=1234, method=pin [BreakEscape] Object not found: non_existent_object Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.654350"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.654181"], ["updated_at", "2025-11-21 21:05:48.654181"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=wrongpassword, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.660574"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.660391"], ["updated_at", "2025-11-21 21:05:48.660391"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=0000, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='0000', result=false Completed 422 Unprocessable Content in 3ms (Views: 0.2ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors ------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.668120"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.667949"], ["updated_at", "2025-11-21 21:05:48.667949"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "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.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.676833"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 7ms (Views: 0.2ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 10.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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-21 21:05:48.682840"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.682544"], ["updated_at", "2025-11-21 21:05:48.682544"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.689708"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.694416"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.694246"], ["updated_at", "2025-11-21 21:05:48.694246"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.699508"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction --------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' --------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.704621"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.704270"], ["updated_at", "2025-11-21 21:05:48.704270"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=, method=unlocked [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) 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 (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\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.722794"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.722565"], ["updated_at", "2025-11-21 21:05:48.722565"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.729467"], ["id", 1]] TRANSACTION (0.2ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.2ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.5ms (4 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.741760"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.741421"], ["updated_at", "2025-11-21 21:05:48.741421"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_key, attempt=, method=key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.748864"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 6ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.754967"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.754680"], ["updated_at", "2025-11-21 21:05:48.754680"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.761599"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail ------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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-21 21:05:48.767146"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.766856"], ["updated_at", "2025-11-21 21:05:48.766856"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"non_existent_room", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=non_existent_room, attempt=1234, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation ----------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.774813"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.774633"], ["updated_at", "2025-11-21 21:05:48.774633"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] 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-21 21:05:48.779554"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 21:05:48.783706"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 21:05:48.783509"], ["updated_at", "2025-11-21 21:05:48.783509"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 21:05:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=terminal_bluetooth, attempt=, method=bluetooth [BreakEscape] Found object: id=terminal_bluetooth, name=Bluetooth Terminal, locked=true, requires=admin_device TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"terminal_bluetooth\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 21:05:48.788450"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.4ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.3ms) begin transaction  (0.6ms) PRAGMA foreign_keys  (0.0ms) PRAGMA defer_foreign_keys  (0.1ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-21 23:40:56', '2025-11-21 23:40:56'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 23:40:56', '2025-11-21 23:40:56'); 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-21 23:40:56', '2025-11-21 23:40:56'); 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-21 23:40:56', '2025-11-21 23:40:56')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (7.1ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:40:56.331119"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:40:56.330405"], ["updated_at", "2025-11-21 23:40:56.330405"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":\"office_pin\"}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_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-21 23:40:56.334523"], ["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-21 23:40:56 +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.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 33ms (Views: 0.4ms | ActiveRecord: 0.4ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:40:56.467243"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:40:56.467011"], ["updated_at", "2025-11-21 23:40:56.467011"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "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-21 23:40:56.469132"], ["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-21 23:40:56 +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.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] Player has not encountered NPC: helper_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:40:56.477393"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:40:56.477211"], ["updated_at", "2025-11-21 23:40:56.477211"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\",\"office_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-21 23:40:56.478824"], ["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-21 23:40:56 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:40:56.484470"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_for_non-existent_NPC ----------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:40:56.489275"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:40:56.489092"], ["updated_at", "2025-11-21 23:40:56.489092"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:40:56.490777"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:40:56 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"fake_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=fake_npc, method=npc [BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin [BreakEscape] NPC not found: fake_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_NPC_doesn't_have_permission_for_that_door ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:40:56.497351"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:40:56.497172"], ["updated_at", "2025-11-21 23:40:56.497172"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_password\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:40:56.498946"], ["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-21 23:40:56 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_NPC_can_unlock_container_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:40:56.506227"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:40:56.506047"], ["updated_at", "2025-11-21 23:40:56.506047"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"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-21 23:40:56.508108"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:40:56 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=helper_npc, method=npc [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=safe_pin [BreakEscape] NPC unlock validated: helper_npc can unlock safe_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:40:56.524379"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 15ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 10.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.4ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.4ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-21 23:41:20', '2025-11-21 23:41:20'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-21 23:41:20', '2025-11-21 23:41:20'); 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-21 23:41:20', '2025-11-21 23:41:20'); 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-21 23:41:20', '2025-11-21 23:41:20')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (5.2ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_NPC_can_unlock_container_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) 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.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.031490"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.030707"], ["updated_at", "2025-11-21 23:41:21.030707"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.5ms) 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-21 23:41:21.034592"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +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.3ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=helper_npc, method=npc [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=safe_pin [BreakEscape] NPC unlock validated: helper_npc can unlock safe_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.150118"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 38ms (Views: 0.5ms | ActiveRecord: 1.0ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.176406"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.176190"], ["updated_at", "2025-11-21 23:41:21.176190"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=door_rfid, attempt=, method=rfid [BreakEscape] Found object: id=door_rfid, name=RFID Door, locked=true, requires=admin_badge TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"door_rfid\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.182607"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.186527"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.186348"], ["updated_at", "2025-11-21 23:41:21.186348"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.191396"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.195618"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.195431"], ["updated_at", "2025-11-21 23:41:21.195431"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"chest_unlocked\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.200607"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.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.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.204400"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.204209"], ["updated_at", "2025-11-21 23:41:21.204209"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "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-21 23:41:21.205928"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"fake_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=fake_npc, method=npc [BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin [BreakEscape] NPC not found: fake_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.213008"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.212836"], ["updated_at", "2025-11-21 23:41:21.212836"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=0000, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='0000', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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-21 23:41:21.233413"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.219937"], ["updated_at", "2025-11-21 23:41:21.219937"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (3.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.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.245201"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.245006"], ["updated_at", "2025-11-21 23:41:21.245006"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\",\"office_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-21 23:41:21.246804"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.251901"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 10.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity ----------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.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-21 23:41:21.256123"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.255945"], ["updated_at", "2025-11-21 23:41:21.255945"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=OpenSesame, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.264398"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.264196"], ["updated_at", "2025-11-21 23:41:21.264196"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=0000, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors ------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.273841"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.273599"], ["updated_at", "2025-11-21 23:41:21.273599"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.279539"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.2ms) begin transaction -------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents -------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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-21 23:41:21.284501"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.284155"], ["updated_at", "2025-11-21 23:41:21.284155"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.291090"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_NPC_doesn't_have_permission_for_that_door ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.295096"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.294919"], ["updated_at", "2025-11-21 23:41:21.294919"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.4ms) 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-21 23:41:21.296652"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.304994"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.304741"], ["updated_at", "2025-11-21 23:41:21.304741"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=wrongpassword, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.323432"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.323171"], ["updated_at", "2025-11-21 23:41:21.323171"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=box_lockpick, attempt=, method=lockpick [BreakEscape] Found object: id=box_lockpick, name=Lockpickable Box, locked=true, requires= TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"box_lockpick\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.328815"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks ----------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.334489"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.334303"], ["updated_at", "2025-11-21 23:41:21.334303"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.340672"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.345306"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.344700"], ["updated_at", "2025-11-21 23:41:21.344700"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"non_existent_object", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=non_existent_object, attempt=1234, method=pin [BreakEscape] Object not found: non_existent_object Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.352910"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.352694"], ["updated_at", "2025-11-21 23:41:21.352694"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":\"office_pin\"}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.354396"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction --------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' --------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.361204"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.361041"], ["updated_at", "2025-11-21 23:41:21.361041"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=, method=unlocked [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.368967"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.368791"], ["updated_at", "2025-11-21 23:41:21.368791"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.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_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.374399"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.379071"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.378899"], ["updated_at", "2025-11-21 23:41:21.378899"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.384841"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.5ms (4 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' -------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.400753"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.400540"], ["updated_at", "2025-11-21 23:41:21.400540"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=, method=unlocked [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED object safe_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation ----------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.408538"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.408338"], ["updated_at", "2025-11-21 23:41:21.408338"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.413516"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.417612"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.417429"], ["updated_at", "2025-11-21 23:41:21.417429"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"invalid_method", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=invalid_method Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.424257"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.424056"], ["updated_at", "2025-11-21 23:41:21.424056"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=scanner_biometric, attempt=, method=biometric [BreakEscape] Found object: id=scanner_biometric, name=Biometric Scanner, locked=true, requires=ceo_fingerprint TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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-21 23:41:21.428900"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly ------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.433125"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.432924"], ["updated_at", "2025-11-21 23:41:21.432924"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.437659"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.442786"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.447411"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.451190"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.451026"], ["updated_at", "2025-11-21 23:41:21.451026"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=terminal_bluetooth, attempt=, method=bluetooth [BreakEscape] Found object: id=terminal_bluetooth, name=Bluetooth Terminal, locked=true, requires=admin_device TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"terminal_bluetooth\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.455705"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail ------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.459101"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.458933"], ["updated_at", "2025-11-21 23:41:21.458933"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"non_existent_room", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=non_existent_room, attempt=1234, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.468819"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.468657"], ["updated_at", "2025-11-21 23:41:21.468657"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_key, attempt=, method=key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.473733"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.477910"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.477722"], ["updated_at", "2025-11-21 23:41:21.477722"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=drawer_key, attempt=, method=key [BreakEscape] Found object: id=drawer_key, name=Locked Drawer, locked=true, requires=drawer_key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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-21 23:41:21.482653"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.486316"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.486148"], ["updated_at", "2025-11-21 23:41:21.486148"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.490833"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.495089"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.494909"], ["updated_at", "2025-11-21 23:41:21.494909"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "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-21 23:41:21.496534"], ["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-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] Player has not encountered NPC: helper_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.503357"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.503144"], ["updated_at", "2025-11-21 23:41:21.503144"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=secret123, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='secret123', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"cabinet_password\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-21 23:41:21.508174"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-21 23:41:21.511990"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-21 23:41:21.511832"], ["updated_at", "2025-11-21 23:41:21.511832"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-21 23:41:21 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] 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-21 23:41:21.517299"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-22 00:12:56', '2025-11-22 00:12:56'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-22 00:12:56', '2025-11-22 00:12:56'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (418560898, 'ceo_exfil', 'CEO Exfiltration', 'Test scenario', 1, 3, '2025-11-22 00:12:56', '2025-11-22 00:12:56'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (636030761, 'test_unpublished', 'Unpublished Test', 'Not visible', 0, 1, '2025-11-22 00:12:56', '2025-11-22 00:12:56')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (5.4ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_NPC_can_unlock_container_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.4ms) SAVEPOINT active_record_1 BreakEscape::Game Create (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\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.196141"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.195256"], ["updated_at", "2025-11-22 00:12:57.195256"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.199633"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +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.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=helper_npc, method=npc [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=safe_pin [BreakEscape] NPC unlock validated: helper_npc can unlock safe_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.316628"], ["id", 1]] BreakEscape::Game Update (0.4ms) 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,\"npcUnlockedTargets\":[\"safe_pin\"]}"], ["updated_at", "2025-11-22 00:12:57.318723"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 40ms (Views: 0.4ms | ActiveRecord: 1.3ms (6 queries, 0 cached) | GC: 10.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.348587"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.348329"], ["updated_at", "2025-11-22 00:12:57.348329"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.355233"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.360996"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.360812"], ["updated_at", "2025-11-22 00:12:57.360812"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=terminal_bluetooth, attempt=, method=bluetooth [BreakEscape] Found object: id=terminal_bluetooth, name=Bluetooth Terminal, locked=true, requires=admin_device TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"terminal_bluetooth\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.367184"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.2ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.372063"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.371809"], ["updated_at", "2025-11-22 00:12:57.371809"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=0000, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.379514"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.379339"], ["updated_at", "2025-11-22 00:12:57.379339"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"non_existent_object", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=non_existent_object, attempt=1234, method=pin [BreakEscape] Object not found: non_existent_object Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity ----------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.386238"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.386070"], ["updated_at", "2025-11-22 00:12:57.386070"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=OpenSesame, method=password Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.392281"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.392093"], ["updated_at", "2025-11-22 00:12:57.392093"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\",\"office_password\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.394801"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.412062"], ["id", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[\"office_pin\"]}"], ["updated_at", "2025-11-22 00:12:57.413223"], ["id", 1]] [BreakEscape] Room office_pin was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 17ms (Views: 0.1ms | ActiveRecord: 0.8ms (6 queries, 0 cached) | GC: 10.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (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\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.417503"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.417325"], ["updated_at", "2025-11-22 00:12:57.417325"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.4ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.420238"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.428856"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.428622"], ["updated_at", "2025-11-22 00:12:57.428622"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=wrongpassword, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail ------------------------------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.437619"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.437277"], ["updated_at", "2025-11-22 00:12:57.437277"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"non_existent_room", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=non_existent_room, attempt=1234, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.445163"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.444968"], ["updated_at", "2025-11-22 00:12:57.444968"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=scanner_biometric, attempt=, method=biometric [BreakEscape] Found object: id=scanner_biometric, name=Biometric Scanner, locked=true, requires=ceo_fingerprint TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"scanner_biometric\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.450344"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.454155"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.453984"], ["updated_at", "2025-11-22 00:12:57.453984"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.3ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"chest_unlocked\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.458867"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.462181"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.462014"], ["updated_at", "2025-11-22 00:12:57.462014"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=drawer_key, attempt=, method=key [BreakEscape] Found object: id=drawer_key, name=Locked Drawer, locked=true, requires=drawer_key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"drawer_key\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.466346"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.5ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation ----------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.469466"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.469303"], ["updated_at", "2025-11-22 00:12:57.469303"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.3ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.476430"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' --------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.492435"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.492207"], ["updated_at", "2025-11-22 00:12:57.492207"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=, method=unlocked [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks ----------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.502285"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.502022"], ["updated_at", "2025-11-22 00:12:57.502022"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.509171"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 6ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.513889"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.513632"], ["updated_at", "2025-11-22 00:12:57.513632"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=0000, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='0000', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors ------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.520728"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.520561"], ["updated_at", "2025-11-22 00:12:57.520561"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.4ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.526931"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.531274"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.531072"], ["updated_at", "2025-11-22 00:12:57.531072"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.537031"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (4 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.546542"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.546330"], ["updated_at", "2025-11-22 00:12:57.546330"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.551249"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.555246"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.555066"], ["updated_at", "2025-11-22 00:12:57.555066"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.559851"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.571337"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.571062"], ["updated_at", "2025-11-22 00:12:57.571062"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"invalid_method", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=invalid_method Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_NPC_doesn't_have_permission_for_that_door ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.579289"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.579126"], ["updated_at", "2025-11-22 00:12:57.579126"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.580739"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.587710"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.587452"], ["updated_at", "2025-11-22 00:12:57.587452"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.594649"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.594477"], ["updated_at", "2025-11-22 00:12:57.594477"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.601040"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_for_non-existent_NPC ----------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.606217"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.605921"], ["updated_at", "2025-11-22 00:12:57.605921"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.608033"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"fake_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=fake_npc, method=npc [BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin [BreakEscape] NPC not found: fake_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents -------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.615328"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.615055"], ["updated_at", "2025-11-22 00:12:57.615055"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=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.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.621078"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.625126"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.624857"], ["updated_at", "2025-11-22 00:12:57.624857"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=box_lockpick, attempt=, method=lockpick [BreakEscape] Found object: id=box_lockpick, name=Lockpickable Box, locked=true, requires= TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"box_lockpick\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.630681"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly ------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.634446"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.634265"], ["updated_at", "2025-11-22 00:12:57.634265"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.643588"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 9ms (Views: 0.2ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.651647"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 6ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.659035"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' -------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.664047"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.663874"], ["updated_at", "2025-11-22 00:12:57.663874"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=, method=unlocked [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED object safe_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.672345"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.672149"], ["updated_at", "2025-11-22 00:12:57.672149"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.4ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_key, attempt=, method=key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.677710"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 1.0ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.682068"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.681873"], ["updated_at", "2025-11-22 00:12:57.681873"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=door_rfid, attempt=, method=rfid [BreakEscape] Found object: id=door_rfid, name=RFID Door, locked=true, requires=admin_badge TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"door_rfid\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.687541"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.691959"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.691786"], ["updated_at", "2025-11-22 00:12:57.691786"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=secret123, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='secret123', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"cabinet_password\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:12:57.696975"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:12:57.701342"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:12:57.701176"], ["updated_at", "2025-11-22 00:12:57.701176"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["updated_at", "2025-11-22 00:12:57.702798"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:12:57 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] Player has not encountered NPC: helper_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.4ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.4ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-22 00:14:06', '2025-11-22 00:14:06'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-22 00:14:06', '2025-11-22 00:14:06'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (418560898, 'ceo_exfil', 'CEO Exfiltration', 'Test scenario', 1, 3, '2025-11-22 00:14:06', '2025-11-22 00:14:06'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (636030761, 'test_unpublished', 'Unpublished Test', 'Not visible', 0, 1, '2025-11-22 00:14:06', '2025-11-22 00:14:06')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.5ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.567924"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.567228"], ["updated_at", "2025-11-22 00:14:06.567228"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.8ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.677099"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 35ms (Views: 0.3ms | ActiveRecord: 1.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.693139"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.692941"], ["updated_at", "2025-11-22 00:14:06.692941"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.695178"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.701474"], ["id", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[\"office_pin\"]}"], ["updated_at", "2025-11-22 00:14:06.702851"], ["id", 1]] [BreakEscape] Room office_pin was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 6ms (Views: 0.2ms | ActiveRecord: 0.8ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.719363"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.719169"], ["updated_at", "2025-11-22 00:14:06.719169"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["updated_at", "2025-11-22 00:14:06.721264"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] Player has not encountered NPC: helper_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_filtered_room_data_marks_NPC-unlocked_door_as_unlocked_(race_condition_fix) --------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.729245"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.729035"], ["updated_at", "2025-11-22 00:14:06.729035"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.730878"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=ceo, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo [BreakEscape] NPC unlock validated: helper_npc can unlock ceo TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"ceo\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.736066"], ["id", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"ceo\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[\"ceo\"]}"], ["updated_at", "2025-11-22 00:14:06.737326"], ["id", 1]] [BreakEscape] Room ceo was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.9ms (6 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.742550"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.742363"], ["updated_at", "2025-11-22 00:14:06.742363"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=secret123, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='secret123', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"cabinet_password\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.747758"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.752255"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.752048"], ["updated_at", "2025-11-22 00:14:06.752048"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=0000, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.775788"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.775045"], ["updated_at", "2025-11-22 00:14:06.775045"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=scanner_biometric, attempt=, method=biometric [BreakEscape] Found object: id=scanner_biometric, name=Biometric Scanner, locked=true, requires=ceo_fingerprint TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"scanner_biometric\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.780338"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.5ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks ----------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.785209"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.785009"], ["updated_at", "2025-11-22 00:14:06.785009"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.790833"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_npcUnlockedTargets_is_initialized_in_new_game_player_state ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.795059"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.794878"], ["updated_at", "2025-11-22 00:14:06.794878"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.801817"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.801639"], ["updated_at", "2025-11-22 00:14:06.801639"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=terminal_bluetooth, attempt=, method=bluetooth [BreakEscape] Found object: id=terminal_bluetooth, name=Bluetooth Terminal, locked=true, requires=admin_device TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"terminal_bluetooth\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.807234"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.811175"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.810953"], ["updated_at", "2025-11-22 00:14:06.810953"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.816063"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.5ms (4 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.824921"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.824717"], ["updated_at", "2025-11-22 00:14:06.824717"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.2ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors ------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.841912"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.841699"], ["updated_at", "2025-11-22 00:14:06.841699"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.6ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.846889"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 1.1ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_NPC_doesn't_have_permission_for_that_door ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.850927"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.850767"], ["updated_at", "2025-11-22 00:14:06.850767"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.852313"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_NPC_can_unlock_container_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.859670"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.859495"], ["updated_at", "2025-11-22 00:14:06.859495"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.861672"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=helper_npc, method=npc [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=safe_pin [BreakEscape] NPC unlock validated: helper_npc can unlock safe_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.866535"], ["id", 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,\"npcUnlockedTargets\":[\"safe_pin\"]}"], ["updated_at", "2025-11-22 00:14:06.867499"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.871559"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.871371"], ["updated_at", "2025-11-22 00:14:06.871371"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=wrongpassword, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_unlock_is_tracked_in_npcUnlockedTargets ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.878582"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.878357"], ["updated_at", "2025-11-22 00:14:06.878357"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.880519"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.885775"], ["id", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[\"office_pin\"]}"], ["updated_at", "2025-11-22 00:14:06.886766"], ["id", 1]] [BreakEscape] Room office_pin was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity ----------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.891010"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.890833"], ["updated_at", "2025-11-22 00:14:06.890833"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=OpenSesame, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly ------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.897953"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.897778"], ["updated_at", "2025-11-22 00:14:06.897778"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.909608"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 11ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 10.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.916138"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.921834"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.927413"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.927228"], ["updated_at", "2025-11-22 00:14:06.927228"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=door_rfid, attempt=, method=rfid [BreakEscape] Found object: id=door_rfid, name=RFID Door, locked=true, requires=admin_badge TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"door_rfid\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.933076"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.937030"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.936859"], ["updated_at", "2025-11-22 00:14:06.936859"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.942192"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation ----------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.947455"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.947258"], ["updated_at", "2025-11-22 00:14:06.947258"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.953255"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction --------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' --------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.957673"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.957459"], ["updated_at", "2025-11-22 00:14:06.957459"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=, method=unlocked [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' -------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.964828"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.964651"], ["updated_at", "2025-11-22 00:14:06.964651"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=, method=unlocked [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED object safe_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.971861"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.971682"], ["updated_at", "2025-11-22 00:14:06.971682"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.979623"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.984041"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.983843"], ["updated_at", "2025-11-22 00:14:06.983843"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"non_existent_object", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=non_existent_object, attempt=1234, method=pin [BreakEscape] Object not found: non_existent_object Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_filtered_room_data_marks_NPC-unlocked_container_as_unlocked ----------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.4ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:06.990598"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:06.990360"], ["updated_at", "2025-11-22 00:14:06.990360"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"npc_safe\",\"type\":\"safe1\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9999\",\"contents\":[{\"type\":\"key\",\"id\":\"master_key\",\"takeable\":true}]}],\"npcs\":[{\"id\":\"helper_npc\",\"unlockable\":[\"npc_safe\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.992077"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:06 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"npc_safe", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=npc_safe, attempt=helper_npc, method=npc [BreakEscape] Found object: id=npc_safe, name=, locked=true, requires=9999 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=npc_safe [BreakEscape] NPC unlock validated: helper_npc can unlock npc_safe TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:06.997655"], ["id", 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,\"npcUnlockedTargets\":[\"npc_safe\"]}"], ["updated_at", "2025-11-22 00:14:06.998646"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (6 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_for_non-existent_NPC ----------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:07.002926"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:07.002750"], ["updated_at", "2025-11-22 00:14:07.002750"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:07.004857"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"fake_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=fake_npc, method=npc [BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin [BreakEscape] NPC not found: fake_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:07.011969"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:07.011767"], ["updated_at", "2025-11-22 00:14:07.011767"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=0000, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='0000', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents -------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:07.019248"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:07.019048"], ["updated_at", "2025-11-22 00:14:07.019048"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:07.024244"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:07.028024"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:07.027851"], ["updated_at", "2025-11-22 00:14:07.027851"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:07.033716"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:07.038458"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:07.038263"], ["updated_at", "2025-11-22 00:14:07.038263"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=box_lockpick, attempt=, method=lockpick [BreakEscape] Found object: id=box_lockpick, name=Lockpickable Box, locked=true, requires= TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"box_lockpick\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:07.045875"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 6ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail ------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:07.049855"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:07.049675"], ["updated_at", "2025-11-22 00:14:07.049675"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"non_existent_room", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=non_existent_room, attempt=1234, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:07.058037"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:07.057828"], ["updated_at", "2025-11-22 00:14:07.057828"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_key, attempt=, method=key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:07.062673"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:07.067407"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:07.067237"], ["updated_at", "2025-11-22 00:14:07.067237"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":\"office_pin\"}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:07.068942"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:07.075947"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:07.075770"], ["updated_at", "2025-11-22 00:14:07.075770"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"chest_unlocked\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:07.081116"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:07.085463"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:07.085299"], ["updated_at", "2025-11-22 00:14:07.085299"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=drawer_key, attempt=, method=key [BreakEscape] Found object: id=drawer_key, name=Locked Drawer, locked=true, requires=drawer_key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"drawer_key\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:14:07.090354"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:14:07.094259"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:14:07.094078"], ["updated_at", "2025-11-22 00:14:07.094078"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:14:07 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"invalid_method", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=invalid_method Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.4ms) 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.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.5ms) PRAGMA foreign_keys  (0.0ms) PRAGMA defer_foreign_keys  (0.1ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-22 00:18:59', '2025-11-22 00:18:59'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-22 00:18:59', '2025-11-22 00:18:59'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (418560898, 'ceo_exfil', 'CEO Exfiltration', 'Test scenario', 1, 3, '2025-11-22 00:18:59', '2025-11-22 00:18:59'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (636030761, 'test_unpublished', 'Unpublished Test', 'Not visible', 0, 1, '2025-11-22 00:18:59', '2025-11-22 00:18:59')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.5ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.231021"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.230168"], ["updated_at", "2025-11-22 00:19:00.230168"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=drawer_key, attempt=, method=key [BreakEscape] Found object: id=drawer_key, name=Locked Drawer, locked=true, requires=drawer_key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"drawer_key\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.344318"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 35ms (Views: 0.2ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.370377"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.370186"], ["updated_at", "2025-11-22 00:19:00.370186"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\",\"office_password\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.372448"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.378035"], ["id", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[\"office_pin\"]}"], ["updated_at", "2025-11-22 00:19:00.379004"], ["id", 1]] [BreakEscape] Room office_pin was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.2ms | ActiveRecord: 0.7ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_NPC_doesn't_have_permission_for_that_door ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.384448"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.384241"], ["updated_at", "2025-11-22 00:19:00.384241"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.386147"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.393456"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.393283"], ["updated_at", "2025-11-22 00:19:00.393283"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=secret123, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='secret123', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"cabinet_password\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.398217"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors ------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.402338"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.402162"], ["updated_at", "2025-11-22 00:19:00.402162"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.5ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.407815"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly ------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.411864"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.411678"], ["updated_at", "2025-11-22 00:19:00.411678"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.416811"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 16ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 10.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.434289"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.439474"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' -------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.444805"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.444608"], ["updated_at", "2025-11-22 00:19:00.444608"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=, method=unlocked [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED object safe_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail ------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.452832"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.452643"], ["updated_at", "2025-11-22 00:19:00.452643"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"non_existent_room", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=non_existent_room, attempt=1234, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.459247"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.459086"], ["updated_at", "2025-11-22 00:19:00.459086"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":\"office_pin\"}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.460749"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.467503"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.467291"], ["updated_at", "2025-11-22 00:19:00.467291"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=door_rfid, attempt=, method=rfid [BreakEscape] Found object: id=door_rfid, name=RFID Door, locked=true, requires=admin_badge TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"door_rfid\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.472941"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.476564"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.476367"], ["updated_at", "2025-11-22 00:19:00.476367"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.481086"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.484935"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.484763"], ["updated_at", "2025-11-22 00:19:00.484763"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=wrongpassword, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.491003"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.490816"], ["updated_at", "2025-11-22 00:19:00.490816"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=scanner_biometric, attempt=, method=biometric [BreakEscape] Found object: id=scanner_biometric, name=Biometric Scanner, locked=true, requires=ceo_fingerprint TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"scanner_biometric\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.506712"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents -------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.511025"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.510861"], ["updated_at", "2025-11-22 00:19:00.510861"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.515704"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.518951"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.518797"], ["updated_at", "2025-11-22 00:19:00.518797"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["updated_at", "2025-11-22 00:19:00.520734"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] Player has not encountered NPC: helper_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.527141"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.526933"], ["updated_at", "2025-11-22 00:19:00.526933"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.532524"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' --------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.537119"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.536940"], ["updated_at", "2025-11-22 00:19:00.536940"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=, method=unlocked [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.543800"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.543638"], ["updated_at", "2025-11-22 00:19:00.543638"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.548080"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation ----------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.552325"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.552140"], ["updated_at", "2025-11-22 00:19:00.552140"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.557507"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_filtered_room_data_marks_NPC-unlocked_container_as_unlocked ----------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.562715"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.562335"], ["updated_at", "2025-11-22 00:19:00.562335"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"npc_safe\",\"type\":\"safe1\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9999\",\"contents\":[{\"type\":\"key\",\"id\":\"master_key\",\"takeable\":true}]}],\"npcs\":[{\"id\":\"helper_npc\",\"unlockable\":[\"npc_safe\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.571692"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +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.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=npc_safe, attempt=helper_npc, method=npc [BreakEscape] Found object: id=npc_safe, name=, locked=true, requires=9999 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=npc_safe [BreakEscape] NPC unlock validated: helper_npc can unlock npc_safe TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.577174"], ["id", 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,\"npcUnlockedTargets\":[\"npc_safe\"]}"], ["updated_at", "2025-11-22 00:19:00.578754"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (6 queries, 0 cached) | GC: 0.0ms) Started GET "/break_escape/games/1/room/lobby" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"lobby"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] Object npc_safe was unlocked by NPC, marking as unlocked [BreakEscape] Serving room data for: lobby Completed 200 OK in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.588373"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.588167"], ["updated_at", "2025-11-22 00:19:00.588167"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.593690"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.598139"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.597966"], ["updated_at", "2025-11-22 00:19:00.597966"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=0000, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='0000', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_unlock_is_tracked_in_npcUnlockedTargets ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.604617"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.604429"], ["updated_at", "2025-11-22 00:19:00.604429"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.606218"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.610812"], ["id", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[\"office_pin\"]}"], ["updated_at", "2025-11-22 00:19:00.612029"], ["id", 1]] [BreakEscape] Room office_pin was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.615833"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.615656"], ["updated_at", "2025-11-22 00:19:00.615656"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks ----------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.623341"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.623161"], ["updated_at", "2025-11-22 00:19:00.623161"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.627977"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.631442"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.631264"], ["updated_at", "2025-11-22 00:19:00.631264"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=box_lockpick, attempt=, method=lockpick [BreakEscape] Found object: id=box_lockpick, name=Lockpickable Box, locked=true, requires= TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"box_lockpick\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.636280"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 7ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 10.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity ----------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.643005"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.642835"], ["updated_at", "2025-11-22 00:19:00.642835"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=OpenSesame, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_npcUnlockedTargets_is_initialized_in_new_game_player_state ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.649679"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.649516"], ["updated_at", "2025-11-22 00:19:00.649516"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.656728"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.656529"], ["updated_at", "2025-11-22 00:19:00.656529"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=0000, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_for_non-existent_NPC ----------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.664342"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.664173"], ["updated_at", "2025-11-22 00:19:00.664173"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.666024"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"fake_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=fake_npc, method=npc [BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin [BreakEscape] NPC not found: fake_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.672113"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.671937"], ["updated_at", "2025-11-22 00:19:00.671937"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"invalid_method", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=invalid_method Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.678590"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.678132"], ["updated_at", "2025-11-22 00:19:00.678132"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_key, attempt=, method=key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.683345"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_NPC_can_unlock_container_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.687857"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.687680"], ["updated_at", "2025-11-22 00:19:00.687680"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.689333"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=helper_npc, method=npc [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=safe_pin [BreakEscape] NPC unlock validated: helper_npc can unlock safe_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.694372"], ["id", 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,\"npcUnlockedTargets\":[\"safe_pin\"]}"], ["updated_at", "2025-11-22 00:19:00.695427"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.699527"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.699317"], ["updated_at", "2025-11-22 00:19:00.699317"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"non_existent_object", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=non_existent_object, attempt=1234, method=pin [BreakEscape] Object not found: non_existent_object Completed 422 Unprocessable Content in 4ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.708313"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.708130"], ["updated_at", "2025-11-22 00:19:00.708130"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.713647"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (4 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_filtered_room_data_marks_NPC-unlocked_door_as_unlocked_(race_condition_fix) --------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.722499"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.722315"], ["updated_at", "2025-11-22 00:19:00.722315"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.724408"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=ceo, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo [BreakEscape] NPC unlock validated: helper_npc can unlock ceo TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.729231"], ["id", 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,\"npcUnlockedTargets\":[\"ceo\"]}"], ["updated_at", "2025-11-22 00:19:00.730640"], ["id", 1]] [BreakEscape] Room ceo was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (6 queries, 0 cached) | GC: 0.0ms) Started GET "/break_escape/games/1/room/ceo" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"ceo"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] Room ceo was unlocked by NPC, marking as unlocked [BreakEscape] Serving room data for: ceo Completed 200 OK in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.740146"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.739913"], ["updated_at", "2025-11-22 00:19:00.739913"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.746523"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:00.750881"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:00.750710"], ["updated_at", "2025-11-22 00:19:00.750710"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:00 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=terminal_bluetooth, attempt=, method=bluetooth [BreakEscape] Found object: id=terminal_bluetooth, name=Bluetooth Terminal, locked=true, requires=admin_device TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"terminal_bluetooth\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:00.756089"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.4ms) PRAGMA foreign_keys  (0.0ms) PRAGMA defer_foreign_keys  (0.2ms) PRAGMA defer_foreign_keys = ON  (0.1ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-22 00:19:51', '2025-11-22 00:19:51'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-22 00:19:51', '2025-11-22 00:19:51'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (418560898, 'ceo_exfil', 'CEO Exfiltration', 'Test scenario', 1, 3, '2025-11-22 00:19:51', '2025-11-22 00:19:51'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (636030761, 'test_unpublished', 'Unpublished Test', 'Not visible', 0, 1, '2025-11-22 00:19:51', '2025-11-22 00:19:51')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.4ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.366083"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.365281"], ["updated_at", "2025-11-22 00:19:51.365281"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":\"office_pin\"}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.369476"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +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.3ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 33ms (Views: 0.3ms | ActiveRecord: 0.5ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.2ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.513590"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.513319"], ["updated_at", "2025-11-22 00:19:51.513319"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.520696"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.2ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.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,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.525688"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.525513"], ["updated_at", "2025-11-22 00:19:51.525513"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=0000, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors ------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.533144"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.532955"], ["updated_at", "2025-11-22 00:19:51.532955"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.539209"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 6ms (Views: 0.2ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.544770"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.544523"], ["updated_at", "2025-11-22 00:19:51.544523"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=scanner_biometric, attempt=, method=biometric [BreakEscape] Found object: id=scanner_biometric, name=Biometric Scanner, locked=true, requires=ceo_fingerprint TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"scanner_biometric\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.550594"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_for_non-existent_NPC ----------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.554687"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.554494"], ["updated_at", "2025-11-22 00:19:51.554494"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.556232"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"fake_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=fake_npc, method=npc [BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin [BreakEscape] NPC not found: fake_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_NPC_doesn't_have_permission_for_that_door ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.562695"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.562478"], ["updated_at", "2025-11-22 00:19:51.562478"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.564686"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.585666"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.585434"], ["updated_at", "2025-11-22 00:19:51.585434"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.6ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=wrongpassword, method=password Completed 422 Unprocessable Content in 3ms (Views: 0.2ms | ActiveRecord: 0.7ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_NPC_can_unlock_container_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.595519"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.595311"], ["updated_at", "2025-11-22 00:19:51.595311"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.597259"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=helper_npc, method=npc [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=safe_pin [BreakEscape] NPC unlock validated: helper_npc can unlock safe_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.602762"], ["id", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[\"safe_pin\"]}"], ["updated_at", "2025-11-22 00:19:51.603706"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.608310"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.608136"], ["updated_at", "2025-11-22 00:19:51.608136"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=door_rfid, attempt=, method=rfid [BreakEscape] Found object: id=door_rfid, name=RFID Door, locked=true, requires=admin_badge TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"door_rfid\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.613451"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' -------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.617084"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.616903"], ["updated_at", "2025-11-22 00:19:51.616903"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=, method=unlocked [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED object safe_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.625031"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.624814"], ["updated_at", "2025-11-22 00:19:51.624814"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"invalid_method", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=invalid_method Completed 422 Unprocessable Content in 3ms (Views: 0.2ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation ----------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.634206"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.634016"], ["updated_at", "2025-11-22 00:19:51.634016"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.639155"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_filtered_room_data_marks_NPC-unlocked_door_as_unlocked_(race_condition_fix) --------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.644825"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.644575"], ["updated_at", "2025-11-22 00:19:51.644575"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"unlockable\":[\"ceo\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]},\"ceo\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"TopSecret123\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.646394"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=ceo, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo [BreakEscape] NPC unlock validated: helper_npc can unlock ceo TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"ceo\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.651375"], ["id", 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,\"npcUnlockedTargets\":[\"ceo\"]}"], ["updated_at", "2025-11-22 00:19:51.652428"], ["id", 1]] [BreakEscape] Room ceo was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 15ms (Views: 0.2ms | ActiveRecord: 0.8ms (6 queries, 0 cached) | GC: 10.0ms) Started GET "/break_escape/games/1/room/ceo" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"ceo"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] Room ceo was unlocked by NPC, marking as unlocked [BreakEscape] Serving room data for: ceo Completed 200 OK in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents -------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.672971"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.672708"], ["updated_at", "2025-11-22 00:19:51.672708"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.677931"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.682381"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.682207"], ["updated_at", "2025-11-22 00:19:51.682207"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=box_lockpick, attempt=, method=lockpick [BreakEscape] Found object: id=box_lockpick, name=Lockpickable Box, locked=true, requires= TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.5ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"box_lockpick\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.688866"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 1.0ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' --------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.693321"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.692859"], ["updated_at", "2025-11-22 00:19:51.692859"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=, method=unlocked [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_npcUnlockedTargets_is_initialized_in_new_game_player_state ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.700412"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.700238"], ["updated_at", "2025-11-22 00:19:51.700238"]] TRANSACTION (0.3ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.707010"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.706842"], ["updated_at", "2025-11-22 00:19:51.706842"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"chest_unlocked\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.712354"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.716314"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.716143"], ["updated_at", "2025-11-22 00:19:51.716143"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.722106"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.5ms (4 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.730831"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.730645"], ["updated_at", "2025-11-22 00:19:51.730645"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=0000, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='0000', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.745356"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.744732"], ["updated_at", "2025-11-22 00:19:51.744732"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.752274"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.752067"], ["updated_at", "2025-11-22 00:19:51.752067"]] TRANSACTION (0.2ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "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.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_key, attempt=, method=key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.759597"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.765560"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.765326"], ["updated_at", "2025-11-22 00:19:51.765326"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=secret123, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='secret123', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"cabinet_password\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.770990"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_filtered_room_data_marks_NPC-unlocked_container_as_unlocked ----------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.775962"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.775764"], ["updated_at", "2025-11-22 00:19:51.775764"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"npc_safe\",\"type\":\"safe1\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9999\",\"contents\":[{\"type\":\"key\",\"id\":\"master_key\",\"takeable\":true}]}],\"npcs\":[{\"id\":\"helper_npc\",\"unlockable\":[\"npc_safe\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.778266"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"npc_safe", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=npc_safe, attempt=helper_npc, method=npc [BreakEscape] Found object: id=npc_safe, name=, locked=true, requires=9999 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=npc_safe [BreakEscape] NPC unlock validated: helper_npc can unlock npc_safe TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"npc_safe\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.784364"], ["id", 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,\"npcUnlockedTargets\":[\"npc_safe\"]}"], ["updated_at", "2025-11-22 00:19:51.785416"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (6 queries, 0 cached) | GC: 0.0ms) Started GET "/break_escape/games/1/room/lobby" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"lobby"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] Object npc_safe was unlocked by NPC, marking as unlocked [BreakEscape] Serving room data for: lobby Completed 200 OK in 2ms (Views: 0.2ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.796000"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.795709"], ["updated_at", "2025-11-22 00:19:51.795709"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=terminal_bluetooth, attempt=, method=bluetooth [BreakEscape] Found object: id=terminal_bluetooth, name=Bluetooth Terminal, locked=true, requires=admin_device TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"terminal_bluetooth\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.802230"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity ----------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.806341"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.806144"], ["updated_at", "2025-11-22 00:19:51.806144"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=OpenSesame, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.813114"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.812925"], ["updated_at", "2025-11-22 00:19:51.812925"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.821396"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.825916"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.825695"], ["updated_at", "2025-11-22 00:19:51.825695"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"non_existent_object", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=non_existent_object, attempt=1234, method=pin [BreakEscape] Object not found: non_existent_object Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.832473"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.832282"], ["updated_at", "2025-11-22 00:19:51.832282"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.837142"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly ------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.843133"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.842900"], ["updated_at", "2025-11-22 00:19:51.842900"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.848795"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.854284"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.859145"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.863110"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.862944"], ["updated_at", "2025-11-22 00:19:51.862944"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\",\"office_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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.864519"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.869758"], ["id", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[\"office_pin\"]}"], ["updated_at", "2025-11-22 00:19:51.870804"], ["id", 1]] [BreakEscape] Room office_pin was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.874939"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.874765"], ["updated_at", "2025-11-22 00:19:51.874765"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["updated_at", "2025-11-22 00:19:51.876442"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] Player has not encountered NPC: helper_npc Completed 422 Unprocessable Content in 4ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 10.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks ----------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.885692"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.885511"], ["updated_at", "2025-11-22 00:19:51.885511"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.890836"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.894569"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.894378"], ["updated_at", "2025-11-22 00:19:51.894378"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.899901"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.904292"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.904120"], ["updated_at", "2025-11-22 00:19:51.904120"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=drawer_key, attempt=, method=key [BreakEscape] Found object: id=drawer_key, name=Locked Drawer, locked=true, requires=drawer_key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"drawer_key\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.909932"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_unlock_is_tracked_in_npcUnlockedTargets ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.913476"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.913312"], ["updated_at", "2025-11-22 00:19:51.913312"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.4ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.915770"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:19:51.921094"], ["id", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[\"office_pin\"]}"], ["updated_at", "2025-11-22 00:19:51.922358"], ["id", 1]] [BreakEscape] Room office_pin was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail ------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:19:51.927717"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:19:51.927403"], ["updated_at", "2025-11-22 00:19:51.927403"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:19:51 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"non_existent_room", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=non_existent_room, attempt=1234, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.4ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.4ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-22 00:20:37', '2025-11-22 00:20:37'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-22 00:20:37', '2025-11-22 00:20: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-22 00:20:37', '2025-11-22 00:20: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-22 00:20:37', '2025-11-22 00:20:37')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.4ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail ------------------------------------------------------------------------ BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.3ms) 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.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.511181"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.510185"], ["updated_at", "2025-11-22 00:20:37.510185"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +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.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=non_existent_room, attempt=1234, method=pin Completed 422 Unprocessable Content in 37ms (Views: 0.4ms | ActiveRecord: 0.5ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.2ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_for_non-existent_NPC ----------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.665452"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.665214"], ["updated_at", "2025-11-22 00:20:37.665214"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.667358"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"fake_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=fake_npc, method=npc [BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin [BreakEscape] NPC not found: fake_npc Completed 422 Unprocessable Content in 3ms (Views: 0.2ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks ----------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.677879"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.677673"], ["updated_at", "2025-11-22 00:20:37.677673"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.683726"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.688461"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.688278"], ["updated_at", "2025-11-22 00:20:37.688278"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors ------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.695891"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.695689"], ["updated_at", "2025-11-22 00:20:37.695689"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.701053"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.705038"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.704860"], ["updated_at", "2025-11-22 00:20:37.704860"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=box_lockpick, attempt=, method=lockpick [BreakEscape] Found object: id=box_lockpick, name=Lockpickable Box, locked=true, requires= TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"box_lockpick\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.710290"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.714118"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.713929"], ["updated_at", "2025-11-22 00:20:37.713929"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.719320"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 18ms (Views: 0.2ms | ActiveRecord: 0.7ms (4 queries, 0 cached) | GC: 10.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents -------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.744453"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.744237"], ["updated_at", "2025-11-22 00:20:37.744237"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.751187"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' --------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.755677"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.755414"], ["updated_at", "2025-11-22 00:20:37.755414"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=, method=unlocked [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_filtered_room_data_marks_NPC-unlocked_door_as_unlocked_(race_condition_fix) --------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.763723"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.763471"], ["updated_at", "2025-11-22 00:20:37.763471"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.765345"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=ceo, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo [BreakEscape] NPC unlock validated: helper_npc can unlock ceo TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"ceo\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.770624"], ["id", 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,\"npcUnlockedTargets\":[\"ceo\"]}"], ["updated_at", "2025-11-22 00:20:37.771629"], ["id", 1]] [BreakEscape] Room ceo was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (6 queries, 0 cached) | GC: 0.0ms) Started GET "/break_escape/games/1/room/ceo" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"ceo"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] Room ceo was unlocked by NPC, marking as unlocked [BreakEscape] Serving room data for: ceo Completed 200 OK in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.781254"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.781070"], ["updated_at", "2025-11-22 00:20:37.781070"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.783078"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.790028"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.789858"], ["updated_at", "2025-11-22 00:20:37.789858"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=scanner_biometric, attempt=, method=biometric [BreakEscape] Found object: id=scanner_biometric, name=Biometric Scanner, locked=true, requires=ceo_fingerprint TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"scanner_biometric\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.794852"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly ------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.798974"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.798778"], ["updated_at", "2025-11-22 00:20:37.798778"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.805011"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 16ms (Views: 0.2ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 10.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.822920"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.829960"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' -------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.834520"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.834310"], ["updated_at", "2025-11-22 00:20:37.834310"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=, method=unlocked [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED object safe_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.843475"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.842875"], ["updated_at", "2025-11-22 00:20:37.842875"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=terminal_bluetooth, attempt=, method=bluetooth [BreakEscape] Found object: id=terminal_bluetooth, name=Bluetooth Terminal, locked=true, requires=admin_device TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"terminal_bluetooth\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.849146"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_NPC_doesn't_have_permission_for_that_door ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.853387"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.853218"], ["updated_at", "2025-11-22 00:20:37.853218"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.854872"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.862460"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.862053"], ["updated_at", "2025-11-22 00:20:37.862053"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=door_rfid, attempt=, method=rfid [BreakEscape] Found object: id=door_rfid, name=RFID Door, locked=true, requires=admin_badge TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"door_rfid\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.867100"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.870568"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.870377"], ["updated_at", "2025-11-22 00:20:37.870377"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\",\"office_password\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.872027"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +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.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.877857"], ["id", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[\"office_pin\"]}"], ["updated_at", "2025-11-22 00:20:37.879155"], ["id", 1]] [BreakEscape] Room office_pin was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 6ms (Views: 0.1ms | ActiveRecord: 0.8ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (7.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,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.883496"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.883301"], ["updated_at", "2025-11-22 00:20:37.883301"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.896673"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.901852"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.901618"], ["updated_at", "2025-11-22 00:20:37.901618"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.908773"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.913794"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.913622"], ["updated_at", "2025-11-22 00:20:37.913622"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=drawer_key, attempt=, method=key [BreakEscape] Found object: id=drawer_key, name=Locked Drawer, locked=true, requires=drawer_key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"drawer_key\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.919936"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.924239"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.923806"], ["updated_at", "2025-11-22 00:20:37.923806"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_key, attempt=, method=key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.930734"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.935542"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.935332"], ["updated_at", "2025-11-22 00:20:37.935332"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=0000, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.943219"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.943053"], ["updated_at", "2025-11-22 00:20:37.943053"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.948028"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.952158"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.951966"], ["updated_at", "2025-11-22 00:20:37.951966"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"invalid_method", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=invalid_method Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_npcUnlockedTargets_is_initialized_in_new_game_player_state ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.958444"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.958258"], ["updated_at", "2025-11-22 00:20:37.958258"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.969589"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.969355"], ["updated_at", "2025-11-22 00:20:37.969355"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.8ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.975426"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.2ms | ActiveRecord: 1.3ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.981221"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.981049"], ["updated_at", "2025-11-22 00:20:37.981049"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["updated_at", "2025-11-22 00:20:37.982773"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] Player has not encountered NPC: helper_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:37.990460"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:37.990291"], ["updated_at", "2025-11-22 00:20:37.990291"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:37 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.5ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"chest_unlocked\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:37.996154"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity ----------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:38.000816"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:38.000638"], ["updated_at", "2025-11-22 00:20:38.000638"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:38 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=OpenSesame, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:38.007596"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:38.007396"], ["updated_at", "2025-11-22 00:20:38.007396"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:38 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"non_existent_object", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=non_existent_object, attempt=1234, method=pin [BreakEscape] Object not found: non_existent_object Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_filtered_room_data_marks_NPC-unlocked_container_as_unlocked ----------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:38.015018"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:38.014831"], ["updated_at", "2025-11-22 00:20:38.014831"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"npc_safe\",\"type\":\"safe1\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9999\",\"contents\":[{\"type\":\"key\",\"id\":\"master_key\",\"takeable\":true}]}],\"npcs\":[{\"id\":\"helper_npc\",\"unlockable\":[\"npc_safe\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:38.016734"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:38 +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.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=npc_safe, attempt=helper_npc, method=npc [BreakEscape] Found object: id=npc_safe, name=, locked=true, requires=9999 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=npc_safe [BreakEscape] NPC unlock validated: helper_npc can unlock npc_safe TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"npc_safe\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:38.021965"], ["id", 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,\"npcUnlockedTargets\":[\"npc_safe\"]}"], ["updated_at", "2025-11-22 00:20:38.022866"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (6 queries, 0 cached) | GC: 0.0ms) Started GET "/break_escape/games/1/room/lobby" for 127.0.0.1 at 2025-11-22 00:20:38 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"lobby"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] Object npc_safe was unlocked by NPC, marking as unlocked [BreakEscape] Serving room data for: lobby Completed 200 OK in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_NPC_can_unlock_container_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:38.032321"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:38.032126"], ["updated_at", "2025-11-22 00:20:38.032126"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:38.033903"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:38 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=helper_npc, method=npc [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=safe_pin [BreakEscape] NPC unlock validated: helper_npc can unlock safe_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:38.041623"], ["id", 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,\"npcUnlockedTargets\":[\"safe_pin\"]}"], ["updated_at", "2025-11-22 00:20:38.042805"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 6ms (Views: 0.1ms | ActiveRecord: 0.9ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation ----------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:38.048717"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:38.048436"], ["updated_at", "2025-11-22 00:20:38.048436"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:38 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:38.054307"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_unlock_is_tracked_in_npcUnlockedTargets ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:38.058966"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:38.058802"], ["updated_at", "2025-11-22 00:20:38.058802"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.4ms) 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:38.060449"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:38 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:38.066811"], ["id", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[\"office_pin\"]}"], ["updated_at", "2025-11-22 00:20:38.068189"], ["id", 1]] [BreakEscape] Room office_pin was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 6ms (Views: 0.1ms | ActiveRecord: 0.9ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:38.073644"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:38.073267"], ["updated_at", "2025-11-22 00:20:38.073267"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:38 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=0000, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='0000', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.2ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:38.083420"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:38.083214"], ["updated_at", "2025-11-22 00:20:38.083214"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:38 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=secret123, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='secret123', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"cabinet_password\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:20:38.089368"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:20:38.094031"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:20:38.093854"], ["updated_at", "2025-11-22 00:20:38.093854"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:20:38 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=wrongpassword, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.6ms) PRAGMA foreign_keys  (0.1ms) PRAGMA defer_foreign_keys  (0.1ms) PRAGMA defer_foreign_keys = ON  (0.0ms) PRAGMA foreign_keys = OFF Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-22 00:21:17', '2025-11-22 00:21:17'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-22 00:21:17', '2025-11-22 00:21:17'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (418560898, 'ceo_exfil', 'CEO Exfiltration', 'Test scenario', 1, 3, '2025-11-22 00:21:17', '2025-11-22 00:21:17'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (636030761, 'test_unpublished', 'Unpublished Test', 'Not visible', 0, 1, '2025-11-22 00:21:17', '2025-11-22 00:21:17')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (5.2ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.197179"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.196289"], ["updated_at", "2025-11-22 00:21:18.196289"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=wrongpassword, method=password Completed 422 Unprocessable Content in 33ms (Views: 0.3ms | ActiveRecord: 0.4ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.339725"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.339057"], ["updated_at", "2025-11-22 00:21:18.339057"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.346015"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.2ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.351080"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.350907"], ["updated_at", "2025-11-22 00:21:18.350907"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.357883"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.357700"], ["updated_at", "2025-11-22 00:21:18.357700"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.362692"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (4 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.371118"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.370950"], ["updated_at", "2025-11-22 00:21:18.370950"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=0000, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='0000', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.377896"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.377727"], ["updated_at", "2025-11-22 00:21:18.377727"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.5ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["updated_at", "2025-11-22 00:21:18.379450"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] Player has not encountered NPC: helper_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.387280"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.386715"], ["updated_at", "2025-11-22 00:21:18.386715"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\",\"office_password\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.400554"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.405274"], ["id", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[\"office_pin\"]}"], ["updated_at", "2025-11-22 00:21:18.406618"], ["id", 1]] [BreakEscape] Room office_pin was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity ----------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.410448"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.410283"], ["updated_at", "2025-11-22 00:21:18.410283"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=OpenSesame, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' --------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.416765"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.416606"], ["updated_at", "2025-11-22 00:21:18.416606"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.9ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=, method=unlocked [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door office_pin Completed 422 Unprocessable Content in 4ms (Views: 0.1ms | ActiveRecord: 1.2ms (3 queries, 0 cached) | GC: 10.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail ------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.427022"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.426819"], ["updated_at", "2025-11-22 00:21:18.426819"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"non_existent_room", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=non_existent_room, attempt=1234, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.3ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.434153"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.433947"], ["updated_at", "2025-11-22 00:21:18.433947"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":\"office_pin\"}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.435805"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 3ms (Views: 0.2ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.444430"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.443961"], ["updated_at", "2025-11-22 00:21:18.443961"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=box_lockpick, attempt=, method=lockpick [BreakEscape] Found object: id=box_lockpick, name=Lockpickable Box, locked=true, requires= TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"box_lockpick\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.450146"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.454875"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.454571"], ["updated_at", "2025-11-22 00:21:18.454571"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=door_rfid, attempt=, method=rfid [BreakEscape] Found object: id=door_rfid, name=RFID Door, locked=true, requires=admin_badge TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"door_rfid\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.461094"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.465304"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.465110"], ["updated_at", "2025-11-22 00:21:18.465110"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.471813"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 16ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors ------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.487560"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.487345"], ["updated_at", "2025-11-22 00:21:18.487345"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.493683"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_filtered_room_data_marks_NPC-unlocked_container_as_unlocked ----------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.497675"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.497445"], ["updated_at", "2025-11-22 00:21:18.497445"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"npc_safe\",\"type\":\"safe1\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9999\",\"contents\":[{\"type\":\"key\",\"id\":\"master_key\",\"takeable\":true}]}],\"npcs\":[{\"id\":\"helper_npc\",\"unlockable\":[\"npc_safe\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.499580"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +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.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=npc_safe, attempt=helper_npc, method=npc [BreakEscape] Found object: id=npc_safe, name=, locked=true, requires=9999 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=npc_safe [BreakEscape] NPC unlock validated: helper_npc can unlock npc_safe TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.5ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"npc_safe\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.505291"], ["id", 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,\"npcUnlockedTargets\":[\"npc_safe\"]}"], ["updated_at", "2025-11-22 00:21:18.506588"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 6ms (Views: 0.1ms | ActiveRecord: 1.1ms (6 queries, 0 cached) | GC: 0.0ms) Started GET "/break_escape/games/1/room/lobby" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"lobby"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] Object npc_safe was unlocked by NPC, marking as unlocked [BreakEscape] Serving room data for: lobby Completed 200 OK in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.517768"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.517581"], ["updated_at", "2025-11-22 00:21:18.517581"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"invalid_method", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=invalid_method Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.525053"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.524854"], ["updated_at", "2025-11-22 00:21:18.524854"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.7ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.531259"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 1.1ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.535950"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.535778"], ["updated_at", "2025-11-22 00:21:18.535778"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_key, attempt=, method=key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.540691"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks ----------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.544633"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.544431"], ["updated_at", "2025-11-22 00:21:18.544431"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.549179"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' -------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.552746"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.552557"], ["updated_at", "2025-11-22 00:21:18.552557"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=, method=unlocked [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED object safe_pin Completed 422 Unprocessable Content in 3ms (Views: 0.1ms | ActiveRecord: 0.4ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly ------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.568992"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.568721"], ["updated_at", "2025-11-22 00:21:18.568721"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "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.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.576356"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 6ms (Views: 0.1ms | ActiveRecord: 1.0ms (5 queries, 0 cached) | GC: 10.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.583381"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.4ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.589862"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents -------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.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,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.595022"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.594732"], ["updated_at", "2025-11-22 00:21:18.594732"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.600581"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_unlock_is_tracked_in_npcUnlockedTargets ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.604214"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.604026"], ["updated_at", "2025-11-22 00:21:18.604026"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.605734"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.610750"], ["id", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[\"office_pin\"]}"], ["updated_at", "2025-11-22 00:21:18.611674"], ["id", 1]] [BreakEscape] Room office_pin was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.616704"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.616416"], ["updated_at", "2025-11-22 00:21:18.616416"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=0000, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.625550"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.625255"], ["updated_at", "2025-11-22 00:21:18.625255"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=secret123, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='secret123', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"cabinet_password\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.631132"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.639364"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.639108"], ["updated_at", "2025-11-22 00:21:18.639108"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"non_existent_object", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=non_existent_object, attempt=1234, method=pin [BreakEscape] Object not found: non_existent_object Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation ----------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.647858"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.647687"], ["updated_at", "2025-11-22 00:21:18.647687"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] 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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.652942"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_NPC_can_unlock_container_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.656912"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.656748"], ["updated_at", "2025-11-22 00:21:18.656748"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.658787"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=helper_npc, method=npc [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=safe_pin [BreakEscape] NPC unlock validated: helper_npc can unlock safe_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.663475"], ["id", 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,\"npcUnlockedTargets\":[\"safe_pin\"]}"], ["updated_at", "2025-11-22 00:21:18.664695"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (6 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.668732"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.668560"], ["updated_at", "2025-11-22 00:21:18.668560"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.673589"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.678148"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.677957"], ["updated_at", "2025-11-22 00:21:18.677957"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +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.2ms) SELECT "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=object, id=scanner_biometric, attempt=, method=biometric [BreakEscape] Found object: id=scanner_biometric, name=Biometric Scanner, locked=true, requires=ceo_fingerprint TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"scanner_biometric\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.684970"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.688474"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.688302"], ["updated_at", "2025-11-22 00:21:18.688302"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=drawer_key, attempt=, method=key [BreakEscape] Found object: id=drawer_key, name=Locked Drawer, locked=true, requires=drawer_key TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"drawer_key\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.693426"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.696932"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.696741"], ["updated_at", "2025-11-22 00:21:18.696741"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in server data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"chest_unlocked\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.701547"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_filtered_room_data_marks_NPC-unlocked_door_as_unlocked_(race_condition_fix) --------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.706551"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.706362"], ["updated_at", "2025-11-22 00:21:18.706362"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.707963"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=ceo, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo [BreakEscape] NPC unlock validated: helper_npc can unlock ceo TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"ceo\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.712906"], ["id", 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,\"npcUnlockedTargets\":[\"ceo\"]}"], ["updated_at", "2025-11-22 00:21:18.714053"], ["id", 1]] [BreakEscape] Room ceo was unlocked by NPC, marking as unlocked TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (6 queries, 0 cached) | GC: 0.0ms) Started GET "/break_escape/games/1/room/ceo" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#room as HTML Parameters: {"id"=>"1", "room_id"=>"ceo"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] Room ceo was unlocked by NPC, marking as unlocked [BreakEscape] Serving room data for: ceo Completed 200 OK in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.722599"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.722008"], ["updated_at", "2025-11-22 00:21:18.722008"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=terminal_bluetooth, attempt=, method=bluetooth [BreakEscape] Found object: id=terminal_bluetooth, name=Bluetooth Terminal, locked=true, requires=admin_device TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"terminal_bluetooth\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.727329"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction --------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_npcUnlockedTargets_is_initialized_in_existing_game_player_state --------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.730737"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.730574"], ["updated_at", "2025-11-22 00:21:18.730574"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.733664"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.733497"], ["updated_at", "2025-11-22 00:21:18.733497"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.735122"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"fake_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=fake_npc, method=npc [BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin [BreakEscape] NPC not found: fake_npc Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_NPC_doesn't_have_permission_for_that_door ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100,\"npcUnlockedTargets\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:21:18.740644"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:21:18.740423"], ["updated_at", "2025-11-22 00:21:18.740423"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"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,\"npcUnlockedTargets\":[]}"], ["updated_at", "2025-11-22 00:21:18.742113"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:21:18 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.3ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-22 00:31:43', '2025-11-22 00:31:43'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-22 00:31:43', '2025-11-22 00:31: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-22 00:31:43', '2025-11-22 00:31: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-22 00:31:43', '2025-11-22 00:31:43')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.3ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly ------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.391461"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.390736"], ["updated_at", "2025-11-22 00:31:43.390736"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.6ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.496830"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 35ms (Views: 0.2ms | ActiveRecord: 1.3ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.523958"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.529662"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.534492"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.534309"], ["updated_at", "2025-11-22 00:31:43.534309"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=door_rfid, attempt=, method=rfid [BreakEscape] Found object: id=door_rfid, name=RFID Door, locked=true, requires=admin_badge TRANSACTION (0.2ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.4ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"door_rfid\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.539847"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_already-unlocked_container_accepts_method='unlocked' ---------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.543775"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.543571"], ["updated_at", "2025-11-22 00:31:43.543571"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"npc_safe\",\"type\":\"safe1\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9999\",\"contents\":[{\"type\":\"key\",\"id\":\"master_key\",\"takeable\":true}]}],\"npcs\":[{\"id\":\"helper_npc\",\"unlockable\":[\"npc_safe\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.545259"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +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.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=npc_safe, attempt=helper_npc, method=npc [BreakEscape] Found object: id=npc_safe, name=, locked=true, requires=9999 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=npc_safe [BreakEscape] NPC unlock validated: helper_npc can unlock npc_safe TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"npc_safe\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.549601"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"npc_safe", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=npc_safe, attempt=, method=unlocked [BreakEscape] Object already unlocked in player state, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.5ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.556794"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.556627"], ["updated_at", "2025-11-22 00:31:43.556627"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=0000, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents -------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.563456"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.563286"], ["updated_at", "2025-11-22 00:31:43.563286"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.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=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.578845"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 14ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 10.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.582475"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.582317"], ["updated_at", "2025-11-22 00:31:43.582317"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.587398"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.4ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation ----------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.591575"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.591406"], ["updated_at", "2025-11-22 00:31:43.591406"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for door not in player state: office_unlocked Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.597978"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.597825"], ["updated_at", "2025-11-22 00:31:43.597825"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.602286"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks ----------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.606054"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.605899"], ["updated_at", "2025-11-22 00:31:43.605899"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.610481"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.613965"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.613760"], ["updated_at", "2025-11-22 00:31:43.613760"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for object not in player state: chest_unlocked Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity ----------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.620084"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.619931"], ["updated_at", "2025-11-22 00:31:43.619931"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=OpenSesame, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.625857"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.625700"], ["updated_at", "2025-11-22 00:31:43.625700"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.629979"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin [BreakEscape] Door already unlocked in player state, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 9ms (Views: 0.1ms | ActiveRecord: 0.5ms (4 queries, 0 cached) | GC: 10.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_for_non-existent_NPC ----------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.644147"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.643987"], ["updated_at", "2025-11-22 00:31:43.643987"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.645481"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"fake_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=fake_npc, method=npc [BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin [BreakEscape] NPC not found: fake_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.651358"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.651203"], ["updated_at", "2025-11-22 00:31:43.651203"]] TRANSACTION (0.3ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=wrongpassword, method=password Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors ------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.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-22 00:31:43.657147"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.656987"], ["updated_at", "2025-11-22 00:31:43.656987"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for door not in player state: office_unlocked Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.663056"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.662905"], ["updated_at", "2025-11-22 00:31:43.662905"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=secret123, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='secret123', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"cabinet_password\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.667798"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.671658"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.671493"], ["updated_at", "2025-11-22 00:31:43.671493"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["updated_at", "2025-11-22 00:31:43.672974"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] Player has not encountered NPC: helper_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.679065"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.678913"], ["updated_at", "2025-11-22 00:31:43.678913"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":\"office_pin\"}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.680381"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail ------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.686069"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.685916"], ["updated_at", "2025-11-22 00:31:43.685916"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"non_existent_room", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=non_existent_room, attempt=1234, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.691754"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.691597"], ["updated_at", "2025-11-22 00:31:43.691597"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_key, attempt=, method=key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.700113"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 7ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 10.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_already-unlocked_door_accepts_method='unlocked' ----------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.703824"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.703670"], ["updated_at", "2025-11-22 00:31:43.703670"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"unlockable\":[\"ceo\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]},\"ceo\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"TopSecret123\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.705781"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=ceo, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo [BreakEscape] NPC unlock validated: helper_npc can unlock ceo TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"ceo\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.710222"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=ceo, attempt=, method=unlocked [BreakEscape] Door already unlocked in player state, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.5ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' -------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.717476"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.717301"], ["updated_at", "2025-11-22 00:31:43.717301"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=, method=unlocked [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for object not in player state: safe_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.723636"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.723472"], ["updated_at", "2025-11-22 00:31:43.723472"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.728143"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.732245"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.732062"], ["updated_at", "2025-11-22 00:31:43.732062"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"non_existent_object", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=non_existent_object, attempt=1234, method=pin [BreakEscape] Object not found: non_existent_object Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.738068"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.737917"], ["updated_at", "2025-11-22 00:31:43.737917"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=terminal_bluetooth, attempt=, method=bluetooth [BreakEscape] Found object: id=terminal_bluetooth, name=Bluetooth Terminal, locked=true, requires=admin_device TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"terminal_bluetooth\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.742354"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.745640"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.745468"], ["updated_at", "2025-11-22 00:31:43.745468"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=drawer_key, attempt=, method=key [BreakEscape] Found object: id=drawer_key, name=Locked Drawer, locked=true, requires=drawer_key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"drawer_key\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.749856"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.754855"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.752819"], ["updated_at", "2025-11-22 00:31:43.752819"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=box_lockpick, attempt=, method=lockpick [BreakEscape] Found object: id=box_lockpick, name=Lockpickable Box, locked=true, requires= TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"box_lockpick\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.759025"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' --------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.762530"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.762380"], ["updated_at", "2025-11-22 00:31:43.762380"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=, method=unlocked [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for door not in player state: office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.768799"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.768648"], ["updated_at", "2025-11-22 00:31:43.768648"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=0000, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='0000', result=false Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.774507"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.774355"], ["updated_at", "2025-11-22 00:31:43.774355"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"invalid_method", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=invalid_method Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.780193"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.780035"], ["updated_at", "2025-11-22 00:31:43.780035"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for object not in player state: chest_unlocked Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_unlock_adds_door_to_unlockedRooms ------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.786614"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.786447"], ["updated_at", "2025-11-22 00:31:43.786447"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.787936"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.792471"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.796434"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.796279"], ["updated_at", "2025-11-22 00:31:43.796279"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_NPC_doesn't_have_permission_for_that_door ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.802724"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.802560"], ["updated_at", "2025-11-22 00:31:43.802560"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_password\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.804150"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_NPC_can_unlock_container_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.810638"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.810456"], ["updated_at", "2025-11-22 00:31:43.810456"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"safe_pin\",\"cabinet_password\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.813269"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=helper_npc, method=npc [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=safe_pin [BreakEscape] NPC unlock validated: helper_npc can unlock safe_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.818094"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.8ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.822320"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.822138"], ["updated_at", "2025-11-22 00:31:43.822138"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=scanner_biometric, attempt=, method=biometric [BreakEscape] Found object: id=scanner_biometric, name=Biometric Scanner, locked=true, requires=ceo_fingerprint TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"scanner_biometric\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.828260"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:31:43.832060"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:31:43.831904"], ["updated_at", "2025-11-22 00:31:43.831904"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\",\"office_password\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.833397"], ["id", 1]] TRANSACTION (0.2ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:31:43 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:31:43.837814"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.4ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TRANSACTION (0.1ms) begin transaction  (0.4ms) 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.2ms) DELETE FROM "break_escape_demo_users"; DELETE FROM "break_escape_missions"; INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-22 00:32:47', '2025-11-22 00:32:47'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-22 00:32:47', '2025-11-22 00:32:47'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (418560898, 'ceo_exfil', 'CEO Exfiltration', 'Test scenario', 1, 3, '2025-11-22 00:32:47', '2025-11-22 00:32:47'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (636030761, 'test_unpublished', 'Unpublished Test', 'Not visible', 0, 1, '2025-11-22 00:32:47', '2025-11-22 00:32:47')  (0.1ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (4.7ms) commit transaction  (0.1ms) PRAGMA foreign_key_check TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_NPC_can_unlock_container_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) 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.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.082969"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.082325"], ["updated_at", "2025-11-22 00:32:48.082325"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"safe_pin\",\"cabinet_password\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.085774"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +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.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=helper_npc, method=npc [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=safe_pin [BreakEscape] NPC unlock validated: helper_npc can unlock safe_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.188859"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 31ms (Views: 0.2ms | ActiveRecord: 0.8ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.214540"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.214054"], ["updated_at", "2025-11-22 00:32:48.214054"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=secret123, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='secret123', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"cabinet_password\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.220484"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.225195"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.224999"], ["updated_at", "2025-11-22 00:32:48.224999"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=wrongpassword, method=password Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.232528"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.232355"], ["updated_at", "2025-11-22 00:32:48.232355"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=0000, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.239689"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.239474"], ["updated_at", "2025-11-22 00:32:48.239474"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.244103"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.248975"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.248782"], ["updated_at", "2025-11-22 00:32:48.248782"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=scanner_biometric, attempt=, method=biometric [BreakEscape] Found object: id=scanner_biometric, name=Biometric Scanner, locked=true, requires=ceo_fingerprint TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"scanner_biometric\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.254321"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent ------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.4ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.258535"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.258363"], ["updated_at", "2025-11-22 00:32:48.258363"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.276086"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 16ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 10.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin [BreakEscape] Door already unlocked in player state, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (4 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.285922"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.285755"], ["updated_at", "2025-11-22 00:32:48.285755"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=0000, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='0000', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC ------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.292470"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.292300"], ["updated_at", "2025-11-22 00:32:48.292300"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["updated_at", "2025-11-22 00:32:48.293909"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] Player has not encountered NPC: helper_npc Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_already-unlocked_door_accepts_method='unlocked' ----------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.301056"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.300886"], ["updated_at", "2025-11-22 00:32:48.300886"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"unlockable\":[\"ceo\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]},\"ceo\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"TopSecret123\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.302768"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=ceo, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo [BreakEscape] NPC unlock validated: helper_npc can unlock ceo TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"ceo\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.307324"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=ceo, attempt=, method=unlocked [BreakEscape] Door already unlocked in player state, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.315597"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.315386"], ["updated_at", "2025-11-22 00:32:48.315386"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=door_rfid, attempt=, method=rfid [BreakEscape] Found object: id=door_rfid, name=RFID Door, locked=true, requires=admin_badge TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"door_rfid\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.320159"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly ------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.323701"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.323502"], ["updated_at", "2025-11-22 00:32:48.323502"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.328445"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.333393"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.348886"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.353706"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.353501"], ["updated_at", "2025-11-22 00:32:48.353501"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_key, attempt=, method=key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.358797"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.364179"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.363987"], ["updated_at", "2025-11-22 00:32:48.363987"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=drawer_key, attempt=, method=key [BreakEscape] Found object: id=drawer_key, name=Locked Drawer, locked=true, requires=drawer_key TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"drawer_key\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.369377"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock -------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.372902"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.372722"], ["updated_at", "2025-11-22 00:32:48.372722"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.377521"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_NPC_doesn't_have_permission_for_that_door ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.381542"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.381380"], ["updated_at", "2025-11-22 00:32:48.381380"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_password\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.382941"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.389399"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.389236"], ["updated_at", "2025-11-22 00:32:48.389236"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=box_lockpick, attempt=, method=lockpick [BreakEscape] Found object: id=box_lockpick, name=Lockpickable Box, locked=true, requires= TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"box_lockpick\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.393680"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation ------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.397026"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.396857"], ["updated_at", "2025-11-22 00:32:48.396857"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=terminal_bluetooth, attempt=, method=bluetooth [BreakEscape] Found object: id=terminal_bluetooth, name=Bluetooth Terminal, locked=true, requires=admin_device TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"terminal_bluetooth\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.402918"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors ------------------------------------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.413127"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.412940"], ["updated_at", "2025-11-22 00:32:48.412940"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in scenario data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.417885"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission ------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.421212"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.421062"], ["updated_at", "2025-11-22 00:32:48.421062"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\",\"office_password\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.422618"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.427117"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation ----------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.430960"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.430769"], ["updated_at", "2025-11-22 00:32:48.430769"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked [BreakEscape] Door is unlocked in scenario data, granting access TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.435282"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array -------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.438986"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.438832"], ["updated_at", "2025-11-22 00:32:48.438832"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":\"office_pin\"}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.440540"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC helper_npc does not have permission to unlock office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.2ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity ----------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.446389"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.446227"], ["updated_at", "2025-11-22 00:32:48.446227"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_password, attempt=OpenSesame, method=password Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_for_non-existent_NPC ----------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.451931"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.451769"], ["updated_at", "2025-11-22 00:32:48.451769"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.453210"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"fake_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=fake_npc, method=npc [BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin [BreakEscape] NPC not found: fake_npc Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction --------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock --------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.458440"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.458282"], ["updated_at", "2025-11-22 00:32:48.458282"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.462678"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail ------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.466398"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.466231"], ["updated_at", "2025-11-22 00:32:48.466231"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=, method=password [BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 [BreakEscape] Password validation: required='secret123', attempt='', result=false Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_NPC_unlock_adds_door_to_unlockedRooms ------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.475273"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.475089"], ["updated_at", "2025-11-22 00:32:48.475089"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.476621"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc [BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin [BreakEscape] NPC unlock validated: helper_npc can unlock office_pin TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.480910"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ----------------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks ----------------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.485589"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.485226"], ["updated_at", "2025-11-22 00:32:48.485226"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.491576"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ------------------------------------------------------------------------ BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail ------------------------------------------------------------------------ BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.495591"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.495374"], ["updated_at", "2025-11-22 00:32:48.495374"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"non_existent_room", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=non_existent_room, attempt=1234, method=pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction --------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' --------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.502120"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.501954"], ["updated_at", "2025-11-22 00:32:48.501954"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=, method=unlocked [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door: office_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ----------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers ----------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.509088"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.508877"], ["updated_at", "2025-11-22 00:32:48.508877"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in scenario data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"chest_unlocked\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.513674"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.517031"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.516869"], ["updated_at", "2025-11-22 00:32:48.516869"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"non_existent_object", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=non_existent_object, attempt=1234, method=pin [BreakEscape] Object not found: non_existent_object Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' -------------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.522998"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.522828"], ["updated_at", "2025-11-22 00:32:48.522828"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=, method=unlocked [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED object: safe_pin Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail -------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.529507"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.529322"], ["updated_at", "2025-11-22 00:32:48.529322"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"invalid_method", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=invalid_method Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction ---------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_already-unlocked_container_accepts_method='unlocked' ---------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.537043"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.536878"], ["updated_at", "2025-11-22 00:32:48.536878"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"npc_safe\",\"type\":\"safe1\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9999\",\"contents\":[{\"type\":\"key\",\"id\":\"master_key\",\"takeable\":true}]}],\"npcs\":[{\"id\":\"helper_npc\",\"unlockable\":[\"npc_safe\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.539081"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +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.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=npc_safe, attempt=helper_npc, method=npc [BreakEscape] Found object: id=npc_safe, name=, locked=true, requires=9999 [BreakEscape] Validating NPC unlock: npc=helper_npc, target=npc_safe [BreakEscape] NPC unlock validated: helper_npc can unlock npc_safe TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"npc_safe\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.543420"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"npc_safe", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=npc_safe, attempt=, method=unlocked [BreakEscape] Object already unlocked in player state, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.5ms (4 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.0ms) begin transaction ---------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation ---------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.6ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.550958"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.550795"], ["updated_at", "2025-11-22 00:32:48.550795"]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked [BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= [BreakEscape] Object is unlocked in scenario data, granting access TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.5ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"chest_unlocked\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.556242"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] TRANSACTION (0.1ms) rollback transaction TRANSACTION (0.1ms) begin transaction -------------------------------------------------------------------------------------------------- BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents -------------------------------------------------------------------------------------------------- BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.1ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:32:48.561311"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:32:48.561129"], ["updated_at", "2025-11-22 00:32:48.561129"]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:32:48 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] [BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin [BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 [BreakEscape] Password validation: required='1234', attempt='1234', result=true TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.566166"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction ActiveRecord::InternalMetadata Load (0.3ms) 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-24 11:19:17', '2025-11-24 11:19:17'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-24 11:19:17', '2025-11-24 11:19:17'); 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-24 11:19:17', '2025-11-24 11:19:17'); 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-24 11:19:17', '2025-11-24 11:19:17')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.7ms) commit transaction  (0.0ms) PRAGMA foreign_key_check 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-24 11:19:17.593710"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.593611"], ["updated_at", "2025-11-24 11:19:17.593611"]] 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-24 11:19:17.595519"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.595480"], ["updated_at", "2025-11-24 11:19:17.595480"]] 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-24 11:19:17.596663"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.596631"], ["updated_at", "2025-11-24 11:19:17.596631"]] 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-24 11:19:17.597131"], ["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-24 11:19:17.598076"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.598045"], ["updated_at", "2025-11-24 11:19:17.598045"]] 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_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-24 11:19:17.599062"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.599031"], ["updated_at", "2025-11-24 11:19:17.599031"]] 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_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-24 11:19:17.600076"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.600045"], ["updated_at", "2025-11-24 11:19:17.600045"]] 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_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-24 11:19:17.601139"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.601099"], ["updated_at", "2025-11-24 11:19:17.601099"]] 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_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-24 11:19:17.602347"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.602315"], ["updated_at", "2025-11-24 11:19:17.602315"]] 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-24 11:19:17.603385"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.603354"], ["updated_at", "2025-11-24 11:19:17.603354"]] 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_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-24 11:19:17.604390"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.604359"], ["updated_at", "2025-11-24 11:19:17.604359"]] 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-24 11:19:17.605370"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.605338"], ["updated_at", "2025-11-24 11:19:17.605338"]] 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_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-24 11:19:17.608786"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.608745"], ["updated_at", "2025-11-24 11:19:17.608745"]] 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-24 11:19:17.609338"], ["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.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-24 11:19:17.610587"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.610357"], ["updated_at", "2025-11-24 11:19:17.610357"]] 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_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-24 11:19:17.611717"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.611684"], ["updated_at", "2025-11-24 11:19:17.611684"]] 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.2ms) 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-24 11:19:17.612925"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.612893"], ["updated_at", "2025-11-24 11:19:17.612893"]] 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-24 11:19:17.613474"], ["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-24 11:19:17.614478"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-24 11:19:17.614427"], ["updated_at", "2025-11-24 11:19:17.614427"]] 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-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) [1mRELEASE 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) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "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 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.1ms) 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.1ms) 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.1ms) 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, "objectives_completed" integer DEFAULT 0, "tasks_completed" integer DEFAULT 0)  (0.0ms) CREATE INDEX "index_break_escape_games_on_mission_id" ON "break_escape_games" ("mission_id")  (0.0ms) CREATE INDEX "index_games_on_player_and_mission_non_unique" 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.1ms) 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, "objectives_completed" integer DEFAULT 0, "tasks_completed" integer DEFAULT 0)  (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 INDEX "tindex_games_on_player_and_mission_non_unique" 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","objectives_completed","tasks_completed") SELECT "id","player_type","player_id","mission_id","scenario_data","player_state","status","started_at","completed_at","score","created_at","updated_at","objectives_completed","tasks_completed" FROM "break_escape_games"  (0.1ms) DROP TABLE "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, "objectives_completed" integer DEFAULT 0, "tasks_completed" integer DEFAULT 0, 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 INDEX "index_games_on_player_and_mission_non_unique" 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","objectives_completed","tasks_completed") SELECT "id","player_type","player_id","mission_id","scenario_data","player_state","status","started_at","completed_at","score","created_at","updated_at","objectives_completed","tasks_completed" 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 (20251128000001)  (0.0ms) INSERT INTO "schema_migrations" (version) VALUES (20251125100000), (20251125000002), (20251125000001), (20251120160000), (20251120155358), (20251120155357);  (0.1ms) 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-28 15:56:49.255954', '2025-11-28 15:56:49.255955') 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', '3e0a3f34fa2f4dba750f1e1da6e1bc2867140556', '2025-11-28 15:56:49.256271', '2025-11-28 15:56:49.256272') 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-28 15:56:49', '2025-11-28 15:56:49'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 15:56:49', '2025-11-28 15:56: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-28 15:56:49', '2025-11-28 15:56: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-28 15:56:49', '2025-11-28 15:56:49')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.6ms) 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.330388"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.330304"], ["updated_at", "2025-11-28 15:56:49.330304"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 15:56: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.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 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.343356"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.343306"], ["updated_at", "2025-11-28 15:56:49.343306"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 15:56: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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.345701"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.345660"], ["updated_at", "2025-11-28 15:56:49.345660"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-28 15:56: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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.348936"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.348891"], ["updated_at", "2025-11-28 15:56:49.348891"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-28 15:56: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.1ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.351281"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.351241"], ["updated_at", "2025-11-28 15:56:49.351241"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.352417"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.352379"], ["updated_at", "2025-11-28 15:56:49.352379"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 15:56: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: 1.5ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 5ms (Views: 2.9ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.359578"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.359537"], ["updated_at", "2025-11-28 15:56:49.359537"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 15:56: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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 15:56:49.361212"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.362553"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.362515"], ["updated_at", "2025-11-28 15:56:49.362515"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 15:56: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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.365786"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.365745"], ["updated_at", "2025-11-28 15:56:49.365745"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-28 15:56: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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.368153"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.368112"], ["updated_at", "2025-11-28 15:56:49.368112"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 15:56: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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.370392"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.370349"], ["updated_at", "2025-11-28 15:56:49.370349"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 15:56: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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.372988"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.372948"], ["updated_at", "2025-11-28 15:56:49.372948"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 15:56:49.373487"], ["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-28 15:56: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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 15:56:49.375020"], ["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::MissionsControllerTest: test_should_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-28 15:56: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.1ms) 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.3ms | GC: 0.4ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 6.3ms | GC: 0.4ms) Completed 200 OK in 7ms (Views: 6.3ms | ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.4ms) 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-28 15:56: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.6ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.6ms | 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_index_should_return_HTML_with_mission_list ------------------------------------------------------------------------------------ Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-28 15:56: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) 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-28 15:56: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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.393200"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.392490"], ["updated_at", "2025-11-28 15:56:49.392490"], ["objectives_completed", 0], ["tasks_completed", 0]] 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.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-28 15:56: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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.396305"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.395702"], ["updated_at", "2025-11-28 15:56:49.395702"], ["objectives_completed", 0], ["tasks_completed", 0]] 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.1ms) 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.398209"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.398179"], ["updated_at", "2025-11-28 15:56:49.398179"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.399269"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.399239"], ["updated_at", "2025-11-28 15:56:49.399239"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 15:56:49.399832"], ["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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.400749"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.400720"], ["updated_at", "2025-11-28 15:56:49.400720"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 15:56:49.401203"], ["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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.402156"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.402127"], ["updated_at", "2025-11-28 15:56:49.402127"], ["objectives_completed", 0], ["tasks_completed", 0]] 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.403176"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.403148"], ["updated_at", "2025-11-28 15:56:49.403148"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 15:56:49.403712"], ["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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.404667"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.404639"], ["updated_at", "2025-11-28 15:56:49.404639"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.405627"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.405598"], ["updated_at", "2025-11-28 15:56:49.405598"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.406685"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.406657"], ["updated_at", "2025-11-28 15:56:49.406657"], ["objectives_completed", 0], ["tasks_completed", 0]] 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.407739"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.407711"], ["updated_at", "2025-11-28 15:56:49.407711"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.408904"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.408872"], ["updated_at", "2025-11-28 15:56:49.408872"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.409904"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.409871"], ["updated_at", "2025-11-28 15:56:49.409871"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 15:56:49.410345"], ["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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.411287"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.411259"], ["updated_at", "2025-11-28 15:56:49.411259"], ["objectives_completed", 0], ["tasks_completed", 0]] 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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] TRANSACTION (0.0ms) SAVEPOINT active_record_1 BreakEscape::Game Create (0.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.412248"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.412221"], ["updated_at", "2025-11-28 15:56:49.412221"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_key_takes_precedence_over_lockpick_attempt ---------------------------------------------------------------------- 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.413437"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.413408"], ["updated_at", "2025-11-28 15:56:49.413408"], ["objectives_completed", 0], ["tasks_completed", 0]] 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.414475"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.414447"], ["updated_at", "2025-11-28 15:56:49.414447"], ["objectives_completed", 0], ["tasks_completed", 0]] 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:56:49.415477"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:56:49.415448"], ["updated_at", "2025-11-28 15:56:49.415448"], ["objectives_completed", 0], ["tasks_completed", 0]] 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 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 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-28 15:59:33', '2025-11-28 15:59:33'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 15:59:33', '2025-11-28 15:59:33'); 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-28 15:59:33', '2025-11-28 15:59:33'); 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-28 15:59:33', '2025-11-28 15:59:33')  (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_should_show_game ------------------------------------------------------- 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:59:33.390862"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:59:33.390779"], ["updated_at", "2025-11-28 15:59:33.390779"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 15:59:33 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"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::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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 8ms (Views: 3.0ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:59:33.407668"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:59:33.407618"], ["updated_at", "2025-11-28 15:59:33.407618"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 15:59:33 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 15:59:33.411339"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:59:33.412987"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:59:33.412937"], ["updated_at", "2025-11-28 15:59:33.412937"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 15:59:33.413502"], ["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-28 15:59:33 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 15:59:33.415290"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:59:33.416700"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:59:33.416659"], ["updated_at", "2025-11-28 15:59:33.416659"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 15:59:33 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:59:33.419479"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:59:33.419439"], ["updated_at", "2025-11-28 15:59:33.419439"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-28 15:59:33 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:59:33.421738"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:59:33.421697"], ["updated_at", "2025-11-28 15:59:33.421697"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 15:59:33 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:59:33.423888"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:59:33.423829"], ["updated_at", "2025-11-28 15:59:33.423829"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 15:59:33 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:59:33.425943"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:59:33.425905"], ["updated_at", "2025-11-28 15:59:33.425905"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-28 15:59:33 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:59:33.427996"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:59:33.427956"], ["updated_at", "2025-11-28 15:59:33.427956"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 15:59:33 +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.1ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.2ms | 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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:59:33.431244"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:59:33.431198"], ["updated_at", "2025-11-28 15:59:33.431198"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-28 15:59:33 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:59:33.434486"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:59:33.434431"], ["updated_at", "2025-11-28 15:59:33.434431"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 15:59:33.435590"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 15:59:33.435552"], ["updated_at", "2025-11-28 15:59:33.435552"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 15:59:33 +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.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-28 16:05:38', '2025-11-28 16:05:38'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 16:05:38', '2025-11-28 16:05:38'); 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-28 16:05:38', '2025-11-28 16:05:38'); 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-28 16:05:38', '2025-11-28 16:05:38')  (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::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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.663496"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.663412"], ["updated_at", "2025-11-28 16:05:38.663412"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.665141"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.665108"], ["updated_at", "2025-11-28 16:05:38.665108"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:05:38.667889"], ["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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.668891"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.668858"], ["updated_at", "2025-11-28 16:05:38.668858"], ["objectives_completed", 0], ["tasks_completed", 0]] 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.670336"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.670307"], ["updated_at", "2025-11-28 16:05:38.670307"], ["objectives_completed", 0], ["tasks_completed", 0]] 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.671480"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.671452"], ["updated_at", "2025-11-28 16:05:38.671452"], ["objectives_completed", 0], ["tasks_completed", 0]] 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.672482"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.672454"], ["updated_at", "2025-11-28 16:05:38.672454"], ["objectives_completed", 0], ["tasks_completed", 0]] 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.673517"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.673489"], ["updated_at", "2025-11-28 16:05:38.673489"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:05:38.673946"], ["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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.674860"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.674831"], ["updated_at", "2025-11-28 16:05:38.674831"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.675905"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.675872"], ["updated_at", "2025-11-28 16:05:38.675872"], ["objectives_completed", 0], ["tasks_completed", 0]] 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.676902"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.676806"], ["updated_at", "2025-11-28 16:05:38.676806"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:05:38.677399"], ["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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.678349"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.678320"], ["updated_at", "2025-11-28 16:05:38.678320"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.679352"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.679322"], ["updated_at", "2025-11-28 16:05:38.679322"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:05:38.679969"], ["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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.680828"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.680799"], ["updated_at", "2025-11-28 16:05:38.680799"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.681906"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.681870"], ["updated_at", "2025-11-28 16:05:38.681870"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.682892"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.682862"], ["updated_at", "2025-11-28 16:05:38.682862"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:38.683919"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:38.683887"], ["updated_at", "2025-11-28 16:05:38.683887"], ["objectives_completed", 0], ["tasks_completed", 0]] 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 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-28 16:05:50', '2025-11-28 16:05:50'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 16:05:50', '2025-11-28 16:05:50'); 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-28 16:05:50', '2025-11-28 16:05:50'); 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-28 16:05:50', '2025-11-28 16:05:50')  (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_show_should_inject_game_configuration ---------------------------------------------------------------------------- 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:05:50.086909"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:05:50.086811"], ["updated_at", "2025-11-28 16:05:50.086811"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:05:50 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"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::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.6ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.8ms | GC: 0.0ms) Completed 200 OK in 8ms (Views: 3.1ms | ActiveRecord: 0.2ms (4 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-28 16:08:45', '2025-11-28 16:08:45'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 16:08:45', '2025-11-28 16:08:45'); 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-28 16:08:45', '2025-11-28 16:08:45'); 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-28 16:08:45', '2025-11-28 16:08:45')  (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_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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:08:45.614070"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:08:45.613965"], ["updated_at", "2025-11-28 16:08:45.613965"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 16:08:45 +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 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:08:45.627266"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:08:45.627213"], ["updated_at", "2025-11-28 16:08:45.627213"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-28 16:08:45 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:08:45.630648"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:08:45.630604"], ["updated_at", "2025-11-28 16:08:45.630604"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:08:45 +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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.6ms | GC: 0.0ms) Completed 200 OK in 5ms (Views: 2.8ms | ActiveRecord: 0.1ms (4 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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:08:45.638359"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:08:45.638312"], ["updated_at", "2025-11-28 16:08:45.638312"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:08:45 +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.1ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.2ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:08:45.641253"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:08:45.641213"], ["updated_at", "2025-11-28 16:08:45.641213"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 16:08:45 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:08:45.642949"], ["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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:08:45.644343"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:08:45.644305"], ["updated_at", "2025-11-28 16:08:45.644305"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-28 16:08:45 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:08:45.646524"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:08:45.646481"], ["updated_at", "2025-11-28 16:08:45.646481"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:08:45.647097"], ["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-28 16:08:45 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:08:45.648763"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:08:45.650144"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:08:45.650104"], ["updated_at", "2025-11-28 16:08:45.650104"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:08:45.651232"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:08:45.651191"], ["updated_at", "2025-11-28 16:08:45.651191"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:08:45 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:08:45.653864"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:08:45.653825"], ["updated_at", "2025-11-28 16:08:45.653825"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:08:45 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:08:45.655951"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:08:45.655913"], ["updated_at", "2025-11-28 16:08:45.655913"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-28 16:08:45 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:08:45.658018"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:08:45.657982"], ["updated_at", "2025-11-28 16:08:45.657982"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:08:45 +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::MissionsControllerTest: test_index_should_display_published_missions --------------------------------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-28 16:08:45 +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.3ms | GC: 0.1ms) Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 8.7ms | GC: 3.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 8.8ms | GC: 3.0ms) Completed 200 OK in 9ms (Views: 8.7ms | ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 3.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::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-28 16:08:45 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:08:45.672875"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:08:45.672209"], ["updated_at", "2025-11-28 16:08:45.672209"], ["objectives_completed", 0], ["tasks_completed", 0]] 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.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-28 16:08:45 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:08:45.675956"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:08:45.675356"], ["updated_at", "2025-11-28 16:08:45.675356"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:08:45 +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.1ms) begin transaction ---------------------------------------------------------- BreakEscape::MissionsControllerTest: test_should_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-28 16:08:45 +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 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-28 16:25:36', '2025-11-28 16:25:36'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 16:25:36', '2025-11-28 16:25:36'); 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-28 16:25:36', '2025-11-28 16:25:36'); 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-28 16:25:36', '2025-11-28 16:25:36')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.6ms) commit transaction  (0.0ms) PRAGMA foreign_key_check 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-28 16:25:36 +0000 Processing by BreakEscape::MissionsController#index as HTML 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]] 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.1ms) 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: 9.1ms | GC: 0.4ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 9.2ms | GC: 0.4ms) Completed 200 OK in 21ms (Views: 10.3ms | ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 3.5ms) 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-28 16:25:36 +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-28 16:25:36 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:25:36.848265"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:25:36.847491"], ["updated_at", "2025-11-28 16:25:36.847491"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 8ms (ActiveRecord: 0.4ms (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-28 16:25:36 +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_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-28 16:25:36 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:25:36.853998"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:25:36.853371"], ["updated_at", "2025-11-28 16:25:36.853371"], ["objectives_completed", 0], ["tasks_completed", 0]] 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::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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:25:36.856124"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:25:36.856080"], ["updated_at", "2025-11-28 16:25:36.856080"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:25:36 +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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.6ms | GC: 0.0ms) Completed 200 OK in 4ms (Views: 1.8ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:25:36.864310"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:25:36.864260"], ["updated_at", "2025-11-28 16:25:36.864260"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-28 16:25:36 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:25:36.869222"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:25:36.869158"], ["updated_at", "2025-11-28 16:25:36.869158"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:25:36 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:25:36.874458"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:25:36.874413"], ["updated_at", "2025-11-28 16:25:36.874413"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-28 16:25:36 +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::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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:25:36.876913"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:25:36.876868"], ["updated_at", "2025-11-28 16:25:36.876868"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 16:25:36 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:25:36.879398"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:25:36.879233"], ["updated_at", "2025-11-28 16:25:36.879233"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:25:36.879953"], ["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-28 16:25:36 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:25:36.881834"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:25:36.883252"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:25:36.883212"], ["updated_at", "2025-11-28 16:25:36.883212"], ["objectives_completed", 0], ["tasks_completed", 0]] 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:25:36.884448"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:25:36.884411"], ["updated_at", "2025-11-28 16:25:36.884411"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:25:36 +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.1ms) 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:25:36.887556"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:25:36.887516"], ["updated_at", "2025-11-28 16:25:36.887516"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:25:36 +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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:25:36.889730"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:25:36.889692"], ["updated_at", "2025-11-28 16:25:36.889692"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-28 16:25:36 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:25:36.891978"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:25:36.891940"], ["updated_at", "2025-11-28 16:25:36.891940"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 16:25:36 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:25:36.893515"], ["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::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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:25:36.894925"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:25:36.894874"], ["updated_at", "2025-11-28 16:25:36.894874"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:25:36 +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 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::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-28 16:26:13', '2025-11-28 16:26:13'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 16:26:13', '2025-11-28 16:26:13'); 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-28 16:26:13', '2025-11-28 16:26:13'); 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-28 16:26:13', '2025-11-28 16:26:13')  (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::MissionsControllerTest: test_should_create_game_and_redirect_when_showing_mission ---------------------------------------------------------------------------------------------- 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 Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-28 16:26:13 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:26:13.824897"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:26:13.824195"], ["updated_at", "2025-11-28 16:26:13.824195"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 9ms (ActiveRecord: 0.4ms (4 queries, 0 cached) | GC: 0.3ms) 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-28 16:26:13 +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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 5.6ms | GC: 0.0ms) Completed 200 OK in 9ms (Views: 6.6ms | ActiveRecord: 0.3ms (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::MissionsControllerTest: test_index_should_return_HTML_with_mission_list ------------------------------------------------------------------------------------ Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-28 16:26:13 +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_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-28 16:26:13 +0000 Processing by BreakEscape::MissionsController#index as HTML 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]] 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_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-28 16:26:13 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:26:13.842796"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:26:13.842142"], ["updated_at", "2025-11-28 16:26:13.842142"], ["objectives_completed", 0], ["tasks_completed", 0]] 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 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-28 16:26:18', '2025-11-28 16:26:18'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 16:26:18', '2025-11-28 16:26: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-28 16:26:18', '2025-11-28 16:26: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-28 16:26:18', '2025-11-28 16:26:18')  (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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:26:18.622239"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:26:18.622127"], ["updated_at", "2025-11-28 16:26:18.622127"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-28 16:26:18 +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 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:26:18.636825"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:26:18.636772"], ["updated_at", "2025-11-28 16:26:18.636772"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:26:18 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:26:18.639470"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:26:18.639427"], ["updated_at", "2025-11-28 16:26:18.639427"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:26:18 +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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.6ms | GC: 0.0ms) Completed 200 OK in 5ms (Views: 2.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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:26:18.647272"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:26:18.647229"], ["updated_at", "2025-11-28 16:26:18.647229"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:26:18 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"missing-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] 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:26:18.649641"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:26:18.649598"], ["updated_at", "2025-11-28 16:26:18.649598"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:26:18 +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.1ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.2ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:26:18.652298"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:26:18.652256"], ["updated_at", "2025-11-28 16:26:18.652256"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 16:26:18 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:26:18.654604"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:26:18.654563"], ["updated_at", "2025-11-28 16:26:18.654563"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-28 16:26:18 +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 0ms (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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:26:18.656767"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:26:18.656724"], ["updated_at", "2025-11-28 16:26:18.656724"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 16:26:18 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:26:18.658427"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:26:18.659818"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:26:18.659780"], ["updated_at", "2025-11-28 16:26:18.659780"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:26:18.660315"], ["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-28 16:26:18 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:26:18.661924"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:26:18.663231"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:26:18.663193"], ["updated_at", "2025-11-28 16:26:18.663193"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-28 16:26:18 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:26:18.665350"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:26:18.665313"], ["updated_at", "2025-11-28 16:26:18.665313"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:26:18 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:26:18.667896"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:26:18.667838"], ["updated_at", "2025-11-28 16:26:18.667838"], ["objectives_completed", 0], ["tasks_completed", 0]] 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 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 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, "environment"]] ActiveRecord::SchemaMigration Load (0.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC Migrating to CreateSecgenVmLabMission (20251128000002) 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, "environment"]] ActiveRecord::SchemaMigration Load (0.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC Migrating to CreateSecgenVmLabMission (20251128000002) 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 Migrating to CreateSecgenVmLabMission (20251128000002) TRANSACTION (0.0ms) begin transaction  (0.1ms) SELECT COUNT(*) FROM break_escape_missions WHERE name = 'secgen_vm_lab' TRANSACTION (0.0ms) rollback transaction 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::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-28 16:48:23', '2025-11-28 16:48:23'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 16:48:23', '2025-11-28 16:48:23'); 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-28 16:48:23', '2025-11-28 16:48:23'); 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-28 16:48:23', '2025-11-28 16:48:23'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-28 16:48:23', '2025-11-28 16:48:23', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (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_ink_endpoint_should_require_npc_parameter -------------------------------------------------------------------------------- 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:48:23.085461"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:48:23.085377"], ["updated_at", "2025-11-28 16:48:23.085377"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-28 16:48:23 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"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]] Completed 400 Bad Request in 3ms (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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:48:23.097138"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:48:23.097086"], ["updated_at", "2025-11-28 16:48:23.097086"], ["objectives_completed", 0], ["tasks_completed", 0]] 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:48:23.098414"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:48:23.098374"], ["updated_at", "2025-11-28 16:48:23.098374"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:48:23 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"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::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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 5ms (Views: 2.9ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:48:23.106121"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:48:23.106077"], ["updated_at", "2025-11-28 16:48:23.106077"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:48:23 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:48:23.109021"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:48:23.108956"], ["updated_at", "2025-11-28 16:48:23.108956"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:48:23 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:48:23.111283"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:48:23.111242"], ["updated_at", "2025-11-28 16:48:23.111242"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:48:23.111864"], ["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-28 16:48:23 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:48:23.115356"], ["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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:48:23.116700"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:48:23.116660"], ["updated_at", "2025-11-28 16:48:23.116660"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 16:48:23 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:48:23.118793"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:48:23.118755"], ["updated_at", "2025-11-28 16:48:23.118755"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-28 16:48:23 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:48:23.120868"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:48:23.120831"], ["updated_at", "2025-11-28 16:48:23.120831"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-28 16:48:23 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:48:23.123571"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:48:23.123532"], ["updated_at", "2025-11-28 16:48:23.123532"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:48:23 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:48:23.125816"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:48:23.125774"], ["updated_at", "2025-11-28 16:48:23.125774"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:48:23 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:48:23.129004"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:48:23.128960"], ["updated_at", "2025-11-28 16:48:23.128960"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 16:48:23 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:48:23.130658"], ["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::MissionsControllerTest: test_index_should_return_HTML_with_mission_list ------------------------------------------------------------------------------------ Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-28 16:48:23 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 8.9ms | GC: 2.7ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 8.9ms | GC: 2.7ms) Completed 200 OK in 10ms (Views: 8.8ms | ActiveRecord: 0.3ms (5 queries, 1 cached) | GC: 2.7ms) 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-28 16:48:23 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.9ms | GC: 0.1ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.0ms | GC: 0.1ms) Completed 200 OK in 1ms (Views: 1.0ms | ActiveRecord: 0.1ms (5 queries, 1 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-28 16:48:23 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:48:23.147458"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:48:23.146776"], ["updated_at", "2025-11-28 16:48:23.146776"], ["objectives_completed", 0], ["tasks_completed", 0]] 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.1ms) 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-28 16:48:23 +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" CACHE 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" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.9ms | GC: 0.1ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.1ms) Completed 200 OK in 1ms (Views: 0.9ms | ActiveRecord: 0.1ms (5 queries, 1 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_create_game_and_redirect_when_showing_mission ---------------------------------------------------------------------------------------------- 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 Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-28 16:48:23 +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.1ms) 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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:48:23.159614"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:48:23.158518"], ["updated_at", "2025-11-28 16:48:23.158518"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 4ms (ActiveRecord: 0.4ms (4 queries, 0 cached) | GC: 0.1ms) BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" 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-28 16:49:48', '2025-11-28 16:49:48'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 16:49:48', '2025-11-28 16:49:48'); 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-28 16:49:48', '2025-11-28 16:49:48'); 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-28 16:49:48', '2025-11-28 16:49:48'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-28 16:49:48', '2025-11-28 16:49:48', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (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_game_setup_has_correct_scenario_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:49:48.320534"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:49:48.320450"], ["updated_at", "2025-11-28 16:49:48.320450"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:49:48.321984"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:49:48.321944"], ["updated_at", "2025-11-28 16:49:48.321944"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-28 16:49:48 +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 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:49:48.335111"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:49:48.335068"], ["updated_at", "2025-11-28 16:49:48.335068"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:49:48 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:49:48.337407"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:49:48.337368"], ["updated_at", "2025-11-28 16:49:48.337368"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:49:48 +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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 5ms (Views: 2.9ms | ActiveRecord: 0.1ms (4 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:49:48.344684"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:49:48.344639"], ["updated_at", "2025-11-28 16:49:48.344639"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-28 16:49:48 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:49:48.347076"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:49:48.347038"], ["updated_at", "2025-11-28 16:49:48.347038"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 16:49:48 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:49:48.349280"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:49:48.349241"], ["updated_at", "2025-11-28 16:49:48.349241"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:49:48 +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.1ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.2ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:49:48.351770"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:49:48.351731"], ["updated_at", "2025-11-28 16:49:48.351731"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 16:49:48 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:49:48.353333"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:49:48.354684"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:49:48.354644"], ["updated_at", "2025-11-28 16:49:48.354644"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:49:48.355207"], ["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-28 16:49:48 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:49:48.356787"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:49:48.358132"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:49:48.358092"], ["updated_at", "2025-11-28 16:49:48.358092"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:49:48 +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.1ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:49:48.361350"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:49:48.361306"], ["updated_at", "2025-11-28 16:49:48.361306"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-28 16:49:48 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:49:48.363478"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:49:48.363438"], ["updated_at", "2025-11-28 16:49:48.363438"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:49:48 +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::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-28 16:49:48 +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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:49:48.370518"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:49:48.369637"], ["updated_at", "2025-11-28 16:49:48.369637"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 3ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.2ms) 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-28 16:49:48 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:49:48.374180"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:49:48.373384"], ["updated_at", "2025-11-28 16:49:48.373384"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_display_published_missions --------------------------------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-28 16:49:48 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 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 6ms (Views: 5.9ms | ActiveRecord: 0.3ms (5 queries, 1 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_index_should_return_HTML_with_mission_list ------------------------------------------------------------------------------------ Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-28 16:49:48 +0000 Processing by BreakEscape::MissionsController#index as HTML 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]] 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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 1.2ms | GC: 0.1ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.3ms | GC: 0.1ms) Completed 200 OK in 2ms (Views: 1.3ms | ActiveRecord: 0.2ms (5 queries, 1 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-28 16:49:48 +0000 Processing by BreakEscape::MissionsController#index as HTML 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]] 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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 1.0ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.1ms | GC: 0.0ms) Completed 200 OK in 2ms (Views: 1.1ms | ActiveRecord: 0.1ms (5 queries, 1 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-28 16:52:52', '2025-11-28 16:52:52'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 16:52:52', '2025-11-28 16:52:52'); 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-28 16:52:52', '2025-11-28 16:52:52'); 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-28 16:52:52', '2025-11-28 16:52:52'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-28 16:52:52', '2025-11-28 16:52:52', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (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_ink_endpoint_should_require_npc_parameter -------------------------------------------------------------------------------- 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:52:52.527844"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:52:52.527757"], ["updated_at", "2025-11-28 16:52:52.527757"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-28 16:52:52 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"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]] Completed 400 Bad Request in 3ms (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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:52:52.539327"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:52:52.539273"], ["updated_at", "2025-11-28 16:52:52.539273"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:52:52.539962"], ["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-28 16:52:52 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:52:52.543958"], ["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 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.1ms) 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:52:52.545477"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:52:52.545437"], ["updated_at", "2025-11-28 16:52:52.545437"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:52:52 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:52:52.547834"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:52:52.547788"], ["updated_at", "2025-11-28 16:52:52.547788"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 16:52:52 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:52:52.550003"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:52:52.549965"], ["updated_at", "2025-11-28 16:52:52.549965"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:52:52 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:52:52.552052"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:52:52.552012"], ["updated_at", "2025-11-28 16:52:52.552012"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-28 16:52:52 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:52:52.554126"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:52:52.554088"], ["updated_at", "2025-11-28 16:52:52.554088"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-28 16:52:52 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:52:52.556876"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:52:52.556815"], ["updated_at", "2025-11-28 16:52:52.556815"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:52:52 +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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 5ms (Views: 2.9ms | ActiveRecord: 0.1ms (4 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:52:52.564012"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:52:52.563970"], ["updated_at", "2025-11-28 16:52:52.563970"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:52:52 +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.1ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.2ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:52:52.566559"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:52:52.566520"], ["updated_at", "2025-11-28 16:52:52.566520"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:52:52 +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.1ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.2ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:52:52.569471"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:52:52.569431"], ["updated_at", "2025-11-28 16:52:52.569431"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 16:52:52 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:52:52.571122"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:52:52.572565"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:52:52.572525"], ["updated_at", "2025-11-28 16:52:52.572525"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:52:52 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.3ms | GC: 0.1ms) 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: 8.8ms | GC: 2.8ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 8.8ms | GC: 2.8ms) Completed 200 OK in 10ms (Views: 8.7ms | ActiveRecord: 0.3ms (5 queries, 1 cached) | GC: 2.8ms) 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-28 16:52:52 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:52:52.586192"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:52:52.585546"], ["updated_at", "2025-11-28 16:52:52.585546"], ["objectives_completed", 0], ["tasks_completed", 0]] 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.2ms) 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-28 16:52:52 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:52:52.589408"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:52:52.588746"], ["updated_at", "2025-11-28 16:52:52.588746"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_return_HTML_with_mission_list ------------------------------------------------------------------------------------ Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-28 16:52:52 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 1.0ms | GC: 0.1ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.0ms | GC: 0.1ms) Completed 200 OK in 1ms (Views: 1.1ms | ActiveRecord: 0.1ms (5 queries, 1 cached) | GC: 0.1ms) 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-28 16:52:52 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.9ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.9ms | ActiveRecord: 0.1ms (5 queries, 1 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 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-28 16:54:55', '2025-11-28 16:54:55'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 16:54:55', '2025-11-28 16:54:55'); 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-28 16:54:55', '2025-11-28 16:54:55'); 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-28 16:54:55', '2025-11-28 16:54:55'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-28 16:54:55', '2025-11-28 16:54:55', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (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_scenario_endpoint_should_return_JSON --------------------------------------------------------------------------- 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:54:55.733377"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:54:55.733294"], ["updated_at", "2025-11-28 16:54:55.733294"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-28 16:54:55 +0000 Processing by BreakEscape::GamesController#scenario as HTML Parameters: {"id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.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 5ms (Views: 0.1ms | ActiveRecord: 0.2ms (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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:54:55.749126"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:54:55.749050"], ["updated_at", "2025-11-28 16:54:55.749050"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:54:55 +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: 2.3ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 2.5ms | GC: 0.0ms) Completed 200 OK in 9ms (Views: 4.6ms | 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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:54:55.761618"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:54:55.761569"], ["updated_at", "2025-11-28 16:54:55.761569"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:54:55 +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.1ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.2ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:54:55.765004"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:54:55.764961"], ["updated_at", "2025-11-28 16:54:55.764961"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:54:55.766134"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:54:55.766096"], ["updated_at", "2025-11-28 16:54:55.766096"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 16:54:55 +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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:54:55.770101"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:54:55.770061"], ["updated_at", "2025-11-28 16:54:55.770061"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:54:55 +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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:54:55.772655"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:54:55.772604"], ["updated_at", "2025-11-28 16:54:55.772604"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 16:54:55 +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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:54:55.775743"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:54:55.775682"], ["updated_at", "2025-11-28 16:54:55.775682"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-28 16:54:55 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"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]] Completed 400 Bad Request 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_should_show_game ------------------------------------------------------- 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:54:55.779637"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:54:55.779560"], ["updated_at", "2025-11-28 16:54:55.779560"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 16:54:55 +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.4ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:54:55.783773"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:54:55.783723"], ["updated_at", "2025-11-28 16:54:55.783723"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:54:55.784424"], ["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-28 16:54:55 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:54:55.786396"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:54:55.787796"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:54:55.787755"], ["updated_at", "2025-11-28 16:54:55.787755"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 16:54:55 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 16:54:55.789536"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:54:55.790954"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:54:55.790913"], ["updated_at", "2025-11-28 16:54:55.790913"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-28 16:54:55 +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::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-28 16:54:55 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:54:55.796243"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:54:55.795563"], ["updated_at", "2025-11-28 16:54:55.795563"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 3ms (ActiveRecord: 0.3ms (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-28 16:54:55 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.3ms | GC: 0.1ms) 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: 6.6ms | GC: 0.5ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 6.6ms | GC: 0.5ms) Completed 200 OK in 7ms (Views: 6.5ms | ActiveRecord: 0.3ms (5 queries, 1 cached) | GC: 0.5ms) 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-28 16:54:55 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 1.4ms | GC: 0.1ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.4ms | GC: 0.1ms) Completed 200 OK in 2ms (Views: 1.5ms | ActiveRecord: 0.2ms (5 queries, 1 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-28 16:54:55 +0000 Processing by BreakEscape::MissionsController#show as HTML Parameters: {"id"=>"418560898"} 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" 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 16:54:55.816852"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 16:54:55.816115"], ["updated_at", "2025-11-28 16:54:55.816115"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 3ms (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-28 16:54:55 +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" CACHE 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" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.9ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.9ms | ActiveRecord: 0.1ms (5 queries, 1 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-28 17:17:22', '2025-11-28 17:17:22'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 17:17:22', '2025-11-28 17:17:22'); 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-28 17:17:22', '2025-11-28 17:17:22'); 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-28 17:17:22', '2025-11-28 17:17:22'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-28 17:17:22', '2025-11-28 17:17:22', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (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_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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:17:22.452407"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:17:22.452313"], ["updated_at", "2025-11-28 17:17:22.452313"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 17:17:22.453314"], ["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-28 17:17:22 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 17:17:22.464858"], ["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 4ms (Views: 0.1ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:17:22.467228"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:17:22.467185"], ["updated_at", "2025-11-28 17:17:22.467185"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-28 17:17:22 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:17:22.469663"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:17:22.469623"], ["updated_at", "2025-11-28 17:17:22.469623"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-28 17:17:22 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:17:22.472437"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:17:22.472397"], ["updated_at", "2025-11-28 17:17:22.472397"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 17:17:22 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 17:17:22.474080"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:17:22.475335"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:17:22.475298"], ["updated_at", "2025-11-28 17:17:22.475298"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 17:17:22 +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.6ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 5ms (Views: 3.0ms | ActiveRecord: 0.1ms (4 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:17:22.483017"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:17:22.482972"], ["updated_at", "2025-11-28 17:17:22.482972"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 17:17:22 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:17:22.486034"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:17:22.485994"], ["updated_at", "2025-11-28 17:17:22.485994"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 17:17:22 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:17:22.488311"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:17:22.488271"], ["updated_at", "2025-11-28 17:17:22.488271"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 17:17:22 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:17:22.490464"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:17:22.490426"], ["updated_at", "2025-11-28 17:17:22.490426"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-28 17:17:22 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:17:22.492535"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:17:22.492499"], ["updated_at", "2025-11-28 17:17:22.492499"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 17:17:22 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:17:22.494551"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:17:22.494513"], ["updated_at", "2025-11-28 17:17:22.494513"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 17:17:22 +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.1ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.2ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:17:22.497168"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:17:22.497129"], ["updated_at", "2025-11-28 17:17:22.497129"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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-28 17:17:22 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:17:22.503662"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:17:22.502940"], ["updated_at", "2025-11-28 17:17:22.502940"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 5ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 2.7ms) 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-28 17:17:22 +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" CACHE BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] BreakEscape::Cybok Load (0.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 5.9ms | GC: 0.2ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 6.1ms | GC: 0.3ms) Completed 200 OK in 7ms (Views: 5.9ms | ActiveRecord: 0.3ms (5 queries, 1 cached) | GC: 0.3ms) 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-28 17:17:22 +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" CACHE 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" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.8ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.1ms) Completed 200 OK in 1ms (Views: 0.9ms | ActiveRecord: 0.1ms (5 queries, 1 cached) | GC: 0.1ms) 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-28 17:17:22 +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" CACHE 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" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.8ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.9ms | ActiveRecord: 0.1ms (5 queries, 1 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::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-28 17:17:22 +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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:17:22.522635"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:17:22.521563"], ["updated_at", "2025-11-28 17:17:22.521563"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 4ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.2ms) 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-28 17:20:23', '2025-11-28 17:20:23'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 17:20:23', '2025-11-28 17:20:23'); 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-28 17:20:23', '2025-11-28 17:20:23'); 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-28 17:20:23', '2025-11-28 17:20:23'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-28 17:20:23', '2025-11-28 17:20:23', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (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_should_show_game ------------------------------------------------------- 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:20:23.846057"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:20:23.845959"], ["updated_at", "2025-11-28 17:20:23.845959"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 17:20:23 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"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::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.6ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.8ms | GC: 0.0ms) Completed 200 OK in 8ms (Views: 3.0ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:20:23.863123"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:20:23.863046"], ["updated_at", "2025-11-28 17:20:23.863046"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 17:20:23 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:20:23.865804"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:20:23.865762"], ["updated_at", "2025-11-28 17:20:23.865762"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-28 17:20:23 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:20:23.868033"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:20:23.867994"], ["updated_at", "2025-11-28 17:20:23.867994"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-28 17:20:23 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:20:23.870333"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:20:23.870294"], ["updated_at", "2025-11-28 17:20:23.870294"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 17:20:23 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:20:23.872557"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:20:23.872520"], ["updated_at", "2025-11-28 17:20:23.872520"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 17:20:23 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:20:23.875692"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:20:23.875655"], ["updated_at", "2025-11-28 17:20:23.875655"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 17:20:23 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 17:20:23.879283"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:20:23.880765"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:20:23.880720"], ["updated_at", "2025-11-28 17:20:23.880720"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 17:20:23 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:20:23.883705"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:20:23.883661"], ["updated_at", "2025-11-28 17:20:23.883661"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-28 17:20:23 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:20:23.886515"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:20:23.886474"], ["updated_at", "2025-11-28 17:20:23.886474"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 17:20:23 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:20:23.888730"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:20:23.888693"], ["updated_at", "2025-11-28 17:20:23.888693"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 17:20:23.889234"], ["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-28 17:20:23 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 17:20:23.890751"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:20:23.892037"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:20:23.892001"], ["updated_at", "2025-11-28 17:20:23.892001"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 17:20:23 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.4ms | GC: 0.2ms) 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: 9.2ms | GC: 3.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 9.3ms | GC: 3.0ms) Completed 200 OK in 10ms (Views: 9.1ms | ActiveRecord: 0.3ms (5 queries, 1 cached) | GC: 3.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-28 17:20:23 +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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:20:23.906446"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:20:23.905778"], ["updated_at", "2025-11-28 17:20:23.905778"], ["objectives_completed", 0], ["tasks_completed", 0]] 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.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-28 17:20:23 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.9ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.0ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 1.0ms | ActiveRecord: 0.1ms (5 queries, 1 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-28 17:20:23 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:20:23.912128"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:20:23.911501"], ["updated_at", "2025-11-28 17:20:23.911501"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_display_published_missions --------------------------------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-28 17:20:23 +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" CACHE 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" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.9ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 1.0ms | ActiveRecord: 0.1ms (5 queries, 1 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 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-28 17:25:47', '2025-11-28 17:25:47'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 17:25:47', '2025-11-28 17:25:47'); 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-28 17:25:47', '2025-11-28 17:25:47'); 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-28 17:25:47', '2025-11-28 17:25:47'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-28 17:25:47', '2025-11-28 17:25:47', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (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_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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:25:47.154361"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:25:47.154275"], ["updated_at", "2025-11-28 17:25:47.154275"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-28 17:25:47 +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.3ms (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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:25:47.168361"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:25:47.168309"], ["updated_at", "2025-11-28 17:25:47.168309"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:25:47.169640"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:25:47.169599"], ["updated_at", "2025-11-28 17:25:47.169599"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 17:25:47 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:25:47.171990"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:25:47.171952"], ["updated_at", "2025-11-28 17:25:47.171952"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 17:25:47 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 17:25:47.173694"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:25:47.175148"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:25:47.175110"], ["updated_at", "2025-11-28 17:25:47.175110"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 17:25:47 +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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 5ms (Views: 2.9ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:25:47.182677"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:25:47.182630"], ["updated_at", "2025-11-28 17:25:47.182630"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 17:25:47 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:25:47.185095"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:25:47.185054"], ["updated_at", "2025-11-28 17:25:47.185054"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-28 17:25:47 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:25:47.187298"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:25:47.187253"], ["updated_at", "2025-11-28 17:25:47.187253"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 17:25:47 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:25:47.189375"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:25:47.189337"], ["updated_at", "2025-11-28 17:25:47.189337"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 17:25:47 +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.1ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.2ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:25:47.192575"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:25:47.192533"], ["updated_at", "2025-11-28 17:25:47.192533"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 17:25:47.193121"], ["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-28 17:25:47 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 17:25:47.194853"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:25:47.196271"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:25:47.196231"], ["updated_at", "2025-11-28 17:25:47.196231"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-28 17:25:47 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:25:47.198506"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:25:47.198468"], ["updated_at", "2025-11-28 17:25:47.198468"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 17:25:47 +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::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-28 17:25:47 +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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:25:47.206542"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:25:47.203241"], ["updated_at", "2025-11-28 17:25:47.203241"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 5ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 2.6ms) 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-28 17:25:47 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 6.3ms | GC: 0.3ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 6.4ms | GC: 0.3ms) Completed 200 OK in 7ms (Views: 6.3ms | ActiveRecord: 0.3ms (5 queries, 1 cached) | GC: 0.3ms) 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-28 17:25:47 +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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 17:25:47.218534"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 17:25:47.217906"], ["updated_at", "2025-11-28 17:25:47.217906"], ["objectives_completed", 0], ["tasks_completed", 0]] 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.4ms (4 queries, 0 cached) | GC: 0.1ms) 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-28 17:25:47 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.9ms | GC: 0.1ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.1ms) Completed 200 OK in 1ms (Views: 1.0ms | ActiveRecord: 0.1ms (5 queries, 1 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-28 17:25:47 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 1.3ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.4ms | GC: 0.0ms) Completed 200 OK in 2ms (Views: 1.4ms | ActiveRecord: 0.2ms (5 queries, 1 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-28 23:58:19', '2025-11-28 23:58:19'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-28 23:58:19', '2025-11-28 23:58: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-28 23:58:19', '2025-11-28 23:58: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-28 23:58:19', '2025-11-28 23:58:19'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-28 23:58:19', '2025-11-28 23:58:19', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (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_show_should_inject_game_configuration ---------------------------------------------------------------------------- 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.030957"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.030772"], ["updated_at", "2025-11-28 23:58:19.030772"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 23:58:19 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"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::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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 8ms (Views: 2.9ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.047591"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.047518"], ["updated_at", "2025-11-28 23:58:19.047518"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 23:58: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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.051825"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.051784"], ["updated_at", "2025-11-28 23:58:19.051784"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 23:58: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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.054172"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.054130"], ["updated_at", "2025-11-28 23:58:19.054130"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 23:58: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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.056788"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.056750"], ["updated_at", "2025-11-28 23:58:19.056750"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-28 23:58:19 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 23:58:19.058450"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.059813"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.059775"], ["updated_at", "2025-11-28 23:58:19.059775"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-28 23:58: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.1ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.2ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.062856"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.062814"], ["updated_at", "2025-11-28 23:58:19.062814"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.064036"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.063997"], ["updated_at", "2025-11-28 23:58:19.063997"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-28 23:58: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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.066343"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.066303"], ["updated_at", "2025-11-28 23:58:19.066303"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 23:58:19.066844"], ["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-28 23:58: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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-28 23:58:19.068472"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.069749"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.069711"], ["updated_at", "2025-11-28 23:58:19.069711"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-28 23:58: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::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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.071979"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.071935"], ["updated_at", "2025-11-28 23:58:19.071935"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-28 23:58:19 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.074601"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.074560"], ["updated_at", "2025-11-28 23:58:19.074560"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-28 23:58: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 0ms (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_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-28 23:58: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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.081920"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.078539"], ["updated_at", "2025-11-28 23:58:19.078539"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 5ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 2.7ms) 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-28 23:58: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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 6.2ms | GC: 0.3ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 6.2ms | GC: 0.3ms) Completed 200 OK in 7ms (Views: 6.1ms | ActiveRecord: 0.3ms (5 queries, 1 cached) | GC: 0.3ms) 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.1ms) 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-28 23:58: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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-28 23:58:19.096018"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-28 23:58:19.095324"], ["updated_at", "2025-11-28 23:58:19.095324"], ["objectives_completed", 0], ["tasks_completed", 0]] 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.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-28 23:58: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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 1.0ms | GC: 0.1ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.1ms | GC: 0.1ms) Completed 200 OK in 2ms (Views: 1.1ms | ActiveRecord: 0.1ms (5 queries, 1 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-28 23:58: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" CACHE 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" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.8ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 1.0ms | ActiveRecord: 0.1ms (5 queries, 1 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-29 00:05:46', '2025-11-29 00:05:46'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-29 00:05:46', '2025-11-29 00:05:46'); 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-29 00:05:46', '2025-11-29 00:05:46'); 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-29 00:05:46', '2025-11-29 00:05:46'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-29 00:05:46', '2025-11-29 00:05:46', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (0.7ms) 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.078939"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.078851"], ["updated_at", "2025-11-29 00:05:46.078851"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 00:05:46.079681"], ["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-29 00:05:46 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 00:05:46.091416"], ["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 4ms (Views: 0.1ms | 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.093673"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.093609"], ["updated_at", "2025-11-29 00:05:46.093609"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-29 00:05:46 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"npc"=>"non-existent", "id"=>"1"} BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.096315"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.096268"], ["updated_at", "2025-11-29 00:05:46.096268"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-29 00:05:46 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.098650"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.098608"], ["updated_at", "2025-11-29 00:05:46.098608"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-29 00:05:46 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.100833"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.100794"], ["updated_at", "2025-11-29 00:05:46.100794"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 00:05:46 +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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 5ms (Views: 2.9ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.107886"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.107849"], ["updated_at", "2025-11-29 00:05:46.107849"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.108950"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.108914"], ["updated_at", "2025-11-29 00:05:46.108914"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 00:05:46 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 00:05:46.110537"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.111807"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.111769"], ["updated_at", "2025-11-29 00:05:46.111769"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-29 00:05:46 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.114443"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.114385"], ["updated_at", "2025-11-29 00:05:46.114385"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 00:05:46 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.117189"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.117146"], ["updated_at", "2025-11-29 00:05:46.117146"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-29 00:05:46 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.119374"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.119334"], ["updated_at", "2025-11-29 00:05:46.119334"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 00:05:46 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.121588"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.121549"], ["updated_at", "2025-11-29 00:05:46.121549"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 00:05:46 +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::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-29 00:05:46 +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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.129973"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.129238"], ["updated_at", "2025-11-29 00:05:46.129238"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.2ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 6ms (ActiveRecord: 0.5ms (4 queries, 0 cached) | GC: 2.7ms) 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-29 00:05:46 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 6.1ms | GC: 0.2ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 6.3ms | GC: 0.4ms) Completed 200 OK in 7ms (Views: 6.1ms | ActiveRecord: 0.4ms (5 queries, 1 cached) | GC: 0.4ms) 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-29 00:05:46 +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" CACHE 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" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.8ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.8ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.8ms | ActiveRecord: 0.1ms (5 queries, 1 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-29 00:05:46 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:05:46.143510"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:05:46.142826"], ["updated_at", "2025-11-29 00:05:46.142826"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_display_published_missions --------------------------------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-29 00:05:46 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.9ms | GC: 0.1ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.1ms) Completed 200 OK in 1ms (Views: 0.9ms | ActiveRecord: 0.1ms (5 queries, 1 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 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-29 00:39:42', '2025-11-29 00:39:42'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-29 00:39:42', '2025-11-29 00:39:42'); 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-29 00:39:42', '2025-11-29 00:39:42'); 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-29 00:39:42', '2025-11-29 00:39:42'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-29 00:39:42', '2025-11-29 00:39:42', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (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_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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.002409"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.002321"], ["updated_at", "2025-11-29 00:39:43.002321"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 00:39: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 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.015875"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.015819"], ["updated_at", "2025-11-29 00:39:43.015819"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-29 00:39:43 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.019223"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.019179"], ["updated_at", "2025-11-29 00:39:43.019179"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 00:39:43 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 00:39:43.020984"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.022384"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.022347"], ["updated_at", "2025-11-29 00:39:43.022347"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-29 00:39:43 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.024516"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.024479"], ["updated_at", "2025-11-29 00:39:43.024479"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 00:39:43 +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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 5ms (Views: 3.0ms | ActiveRecord: 0.1ms (4 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.032069"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.032019"], ["updated_at", "2025-11-29 00:39:43.032019"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 00:39:43 +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.1ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.035027"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.034967"], ["updated_at", "2025-11-29 00:39:43.034967"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-29 00:39:43 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.037309"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.037269"], ["updated_at", "2025-11-29 00:39:43.037269"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 00:39:43.037849"], ["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-29 00:39:43 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 00:39:43.039435"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.040707"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.040668"], ["updated_at", "2025-11-29 00:39:43.040668"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-29 00:39:43 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.042814"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.042775"], ["updated_at", "2025-11-29 00:39:43.042775"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 00:39:43 +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.1ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.2ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.045920"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.045873"], ["updated_at", "2025-11-29 00:39:43.045873"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-29 00:39:43 +0000 Processing by BreakEscape::GamesController#ink as HTML Parameters: {"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]] 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.048198"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.048155"], ["updated_at", "2025-11-29 00:39:43.048155"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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-29 00:39:43 +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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.051893"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.051180"], ["updated_at", "2025-11-29 00:39:43.051180"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 5ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 2.5ms) 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-29 00:39:43 +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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 00:39:43.058193"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 00:39:43.057394"], ["updated_at", "2025-11-29 00:39:43.057394"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 3ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.3ms) 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-29 00:39:43 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 6.1ms | GC: 0.1ms) 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.1ms | ActiveRecord: 0.3ms (5 queries, 1 cached) | GC: 0.2ms) 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-29 00:39:43 +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" CACHE 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" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.8ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 1.0ms | ActiveRecord: 0.1ms (5 queries, 1 cached) | GC: 0.1ms) 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-29 00:39:43 +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" CACHE 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" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.8ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.8ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.9ms | ActiveRecord: 0.1ms (5 queries, 1 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 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-29 01:39:30', '2025-11-29 01:39:30'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-29 01:39:30', '2025-11-29 01:39:30'); 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-29 01:39:30', '2025-11-29 01:39:30'); 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-29 01:39:30', '2025-11-29 01:39:30'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-29 01:39:30', '2025-11-29 01:39:30', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (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_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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:39:30.937304"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:39:30.937195"], ["updated_at", "2025-11-29 01:39:30.937195"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 01:39:30.938409"], ["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-29 01:39:30 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 01:39:30.952691"], ["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 5ms (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::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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:39:30.955442"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:39:30.955393"], ["updated_at", "2025-11-29 01:39:30.955393"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 01:39:30 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:39:30.957922"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:39:30.957876"], ["updated_at", "2025-11-29 01:39:30.957876"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 01:39:30 +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.6ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.8ms | GC: 0.0ms) Completed 200 OK in 7ms (Views: 3.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:39:30.967352"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:39:30.967285"], ["updated_at", "2025-11-29 01:39:30.967285"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:39:30.968496"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:39:30.968454"], ["updated_at", "2025-11-29 01:39:30.968454"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-29 01:39:30 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:39:30.970968"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:39:30.970930"], ["updated_at", "2025-11-29 01:39:30.970930"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 01:39:30 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 01:39:30.972731"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:39:30.974095"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:39:30.974056"], ["updated_at", "2025-11-29 01:39:30.974056"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-29 01:39:30 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:39:30.976807"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:39:30.976768"], ["updated_at", "2025-11-29 01:39:30.976768"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 01:39:30 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:39:30.979399"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:39:30.979360"], ["updated_at", "2025-11-29 01:39:30.979360"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-29 01:39:30 +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 0ms (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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:39:30.981473"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:39:30.981434"], ["updated_at", "2025-11-29 01:39:30.981434"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-29 01:39:30 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:39:30.983539"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:39:30.983499"], ["updated_at", "2025-11-29 01:39:30.983499"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-29 01:39:30 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:39:30.985712"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:39:30.985671"], ["updated_at", "2025-11-29 01:39:30.985671"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 01:39:30 +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::MissionsControllerTest: test_should_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-29 01:39:30 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 10.4ms | GC: 3.1ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 10.5ms | GC: 3.1ms) Completed 200 OK in 11ms (Views: 10.4ms | ActiveRecord: 0.3ms (5 queries, 1 cached) | GC: 3.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-29 01:39:31 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:39:31.003939"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:39:31.003054"], ["updated_at", "2025-11-29 01:39:31.003054"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Redirected to http://www.example.com/break_escape/games/1 Completed 302 Found in 3ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.2ms) 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-29 01:39:31 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 1.0ms | GC: 0.1ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.0ms | GC: 0.1ms) Completed 200 OK in 1ms (Views: 1.0ms | ActiveRecord: 0.1ms (5 queries, 1 cached) | GC: 0.1ms) 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-29 01:39:31 +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" CACHE 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" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.8ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 1.0ms | ActiveRecord: 0.1ms (5 queries, 1 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-29 01:39:31 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:39:31.017693"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:39:31.017018"], ["updated_at", "2025-11-29 01:39:31.017018"], ["objectives_completed", 0], ["tasks_completed", 0]] 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.1ms) TRANSACTION (0.1ms) 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-29 01:43:57', '2025-11-29 01:43:57'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-29 01:43:57', '2025-11-29 01:43:57'); 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-29 01:43:57', '2025-11-29 01:43:57'); 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-29 01:43:57', '2025-11-29 01:43:57'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-29 01:43:57', '2025-11-29 01:43:57', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:43:57.674256"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:43:57.674165"], ["updated_at", "2025-11-29 01:43:57.674165"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 01:43:57 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"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::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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 8ms (Views: 3.0ms | ActiveRecord: 0.2ms (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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:43:57.691459"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:43:57.691404"], ["updated_at", "2025-11-29 01:43:57.691404"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 01:43:57 +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.1ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.2ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:43:57.694948"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:43:57.694904"], ["updated_at", "2025-11-29 01:43:57.694904"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 01:43:57 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 01:43:57.698500"], ["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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:43:57.699991"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:43:57.699950"], ["updated_at", "2025-11-29 01:43:57.699950"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-29 01:43:57 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:43:57.702297"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:43:57.702253"], ["updated_at", "2025-11-29 01:43:57.702253"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:43:57.703468"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:43:57.703429"], ["updated_at", "2025-11-29 01:43:57.703429"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-29 01:43:57 +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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:43:57.705660"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:43:57.705623"], ["updated_at", "2025-11-29 01:43:57.705623"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-29 01:43:57 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:43:57.708263"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:43:57.708224"], ["updated_at", "2025-11-29 01:43:57.708224"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-29 01:43:57 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:43:57.710331"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:43:57.710293"], ["updated_at", "2025-11-29 01:43:57.710293"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 01:43:57.710818"], ["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-29 01:43:57 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 01:43:57.712349"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:43:57.713640"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:43:57.713600"], ["updated_at", "2025-11-29 01:43:57.713600"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-29 01:43:57 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:43:57.716147"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:43:57.716107"], ["updated_at", "2025-11-29 01:43:57.716107"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 01:43:57 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:43:57.718872"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:43:57.718826"], ["updated_at", "2025-11-29 01:43:57.718826"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 01:43:57 +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-29 01:43:57 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 8.9ms | GC: 2.8ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 8.9ms | GC: 2.8ms) Completed 200 OK in 10ms (Views: 8.6ms | ActiveRecord: 0.5ms (5 queries, 1 cached) | GC: 2.8ms) 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_index_should_return_HTML_with_mission_list ------------------------------------------------------------------------------------ Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-29 01:43:57 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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: 1.0ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.0ms | GC: 0.0ms) Completed 200 OK in 2ms (Views: 1.0ms | ActiveRecord: 0.1ms (5 queries, 1 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-29 01:43:57 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:43:57.739651"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:43:57.738891"], ["updated_at", "2025-11-29 01:43:57.738891"], ["objectives_completed", 0], ["tasks_completed", 0]] 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_get_index ---------------------------------------------------------- Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-29 01:43:57 +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" CACHE 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.1ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" IN (?, ?) [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898], ["cybokable_id", 899573729]] 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/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.8ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.9ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 1.0ms | ActiveRecord: 0.1ms (5 queries, 1 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-29 01:43:57 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:43:57.745006"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:43:57.744364"], ["updated_at", "2025-11-29 01:43:57.744364"], ["objectives_completed", 0], ["tasks_completed", 0]] 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.2ms) 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-29 01:57:34', '2025-11-29 01:57:34'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-29 01:57:34', '2025-11-29 01:57:34'); 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-29 01:57:34', '2025-11-29 01:57:34'); 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-29 01:57:34', '2025-11-29 01:57:34'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-29 01:57:34', '2025-11-29 01:57:34', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:57:34.299350"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:57:34.299257"], ["updated_at", "2025-11-29 01:57:34.299257"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-29 01:57:34 +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 5ms (Views: 0.1ms | ActiveRecord: 0.3ms (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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:57:34.316455"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:57:34.316403"], ["updated_at", "2025-11-29 01:57:34.316403"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 01:57:34 +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.6ms | GC: 0.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.0ms) Completed 200 OK in 7ms (Views: 3.5ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:57:34.326652"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:57:34.326593"], ["updated_at", "2025-11-29 01:57:34.326593"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-29 01:57:34 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:57:34.329345"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:57:34.329303"], ["updated_at", "2025-11-29 01:57:34.329303"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-29 01:57:34 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:57:34.331714"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:57:34.331648"], ["updated_at", "2025-11-29 01:57:34.331648"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 01:57:34 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:57:34.333919"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:57:34.333870"], ["updated_at", "2025-11-29 01:57:34.333870"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-29 01:57:34 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:57:34.336097"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:57:34.336056"], ["updated_at", "2025-11-29 01:57:34.336056"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-29 01:57:34 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:57:34.338392"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:57:34.338350"], ["updated_at", "2025-11-29 01:57:34.338350"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:57:34.339649"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:57:34.339592"], ["updated_at", "2025-11-29 01:57:34.339592"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 01:57:34 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:57:34.342655"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:57:34.342611"], ["updated_at", "2025-11-29 01:57:34.342611"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 01:57:34 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 01:57:34.344485"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:57:34.345939"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:57:34.345894"], ["updated_at", "2025-11-29 01:57:34.345894"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 01:57:34 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 01:57:34.348845"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 01:57:34.348803"], ["updated_at", "2025-11-29 01:57:34.348803"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 01:57:34.349373"], ["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-29 01:57:34 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 01:57:34.351035"], ["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 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::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-29 12:15:49', '2025-11-29 12:15:49'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-29 12:15:49', '2025-11-29 12:15: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-29 12:15:49', '2025-11-29 12:15: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-29 12:15:49', '2025-11-29 12:15:49'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-29 12:15:49', '2025-11-29 12:15:49', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (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_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.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 12:15:49.731251"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 12:15:49.731106"], ["updated_at", "2025-11-29 12:15:49.731106"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 12:15:49 +0000 Processing by BreakEscape::GamesController#unlock as HTML Parameters: {"targetType"=>"door", "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=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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 12:15:49.743134"], ["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::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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 12:15:49.745223"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 12:15:49.745182"], ["updated_at", "2025-11-29 12:15:49.745182"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 12:15:49 +0000 Processing by BreakEscape::GamesController#show as HTML Parameters: {"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::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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.6ms | GC: 0.0ms) Completed 200 OK in 5ms (Views: 2.8ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 12:15:49.753273"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 12:15:49.753227"], ["updated_at", "2025-11-29 12:15:49.753227"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-29 12:15: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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* 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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 12:15:49.756194"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 12:15:49.756150"], ["updated_at", "2025-11-29 12:15:49.756150"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-29 12:15: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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 12:15:49.758572"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 12:15:49.758511"], ["updated_at", "2025-11-29 12:15:49.758511"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-29 12:15: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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 12:15:49.760769"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 12:15:49.760730"], ["updated_at", "2025-11-29 12:15:49.760730"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 12:15: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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 12:15:49.763515"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 12:15:49.763457"], ["updated_at", "2025-11-29 12:15:49.763457"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 12:15:49.764021"], ["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-29 12:15: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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 12:15:49.765550"], ["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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 12:15:49.766846"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 12:15:49.766811"], ["updated_at", "2025-11-29 12:15:49.766811"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 12:15: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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 12:15:49.768923"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 12:15:49.768881"], ["updated_at", "2025-11-29 12:15:49.768881"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_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.1ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 12:15:49.770071"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 12:15:49.770019"], ["updated_at", "2025-11-29 12:15:49.770019"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-29 12:15: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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 12:15:49.772238"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 12:15:49.772200"], ["updated_at", "2025-11-29 12:15:49.772200"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 12:15: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.1ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.2ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 12:15:49.774813"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 12:15:49.774775"], ["updated_at", "2025-11-29 12:15:49.774775"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-29 12:15: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 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.1ms) 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-29 15:58:43', '2025-11-29 15:58:43'); INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-29 15:58:43', '2025-11-29 15:58: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-29 15:58:43', '2025-11-29 15:58: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-29 15:58:43', '2025-11-29 15:58:43'); INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (899573729, 'secgen_vm_lab', 'SecGen VM Lab - Linux Introduction', 'Test VM and flag integration with SecGen scenario', 1, 2, '2025-11-29 15:58:43', '2025-11-29 15:58:43', 'labs/introducing_attacks/1_intro_linux.xml', 'vm_labs')  (0.0ms) PRAGMA defer_foreign_keys = 0  (0.0ms) PRAGMA foreign_keys = 1 TRANSACTION (2.4ms) 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.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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 15:58:43.307093"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 15:58:43.307002"], ["updated_at", "2025-11-29 15:58:43.307002"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-29 15:58:43 +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 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 15:58:43.323342"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 15:58:43.323294"], ["updated_at", "2025-11-29 15:58:43.323294"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-29 15:58:43 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 15:58:43.325685"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 15:58:43.325646"], ["updated_at", "2025-11-29 15:58:43.325646"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 15:58: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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] BreakEscape::DemoUser Load (0.0ms) SELECT "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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 15:58:43.327763"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 15:58:43.327725"], ["updated_at", "2025-11-29 15:58:43.327725"], ["objectives_completed", 0], ["tasks_completed", 0]] 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 15:58:43.328946"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 15:58:43.328907"], ["updated_at", "2025-11-29 15:58:43.328907"], ["objectives_completed", 0], ["tasks_completed", 0]] 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 15:58:43.329464"], ["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-29 15:58:43 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 15:58:43.331053"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 15:58:43.332450"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 15:58:43.332410"], ["updated_at", "2025-11-29 15:58:43.332410"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 15:58:43 +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.0ms) Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.6ms | GC: 0.0ms) Completed 200 OK in 7ms (Views: 3.6ms | ActiveRecord: 0.1ms (4 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 15:58:43.342244"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 15:58:43.342200"], ["updated_at", "2025-11-29 15:58:43.342200"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-29 15:58:43 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 15:58:43.344593"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 15:58:43.344552"], ["updated_at", "2025-11-29 15:58:43.344552"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 15:58:43 +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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 15:58:43.347589"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 15:58:43.347524"], ["updated_at", "2025-11-29 15:58:43.347524"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-29 15:58:43 +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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["updated_at", "2025-11-29 15:58:43.349438"], ["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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 15:58:43.350849"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 15:58:43.350809"], ["updated_at", "2025-11-29 15:58:43.350809"], ["objectives_completed", 0], ["tasks_completed", 0]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-29 15:58:43 +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.1ms | GC: 0.0ms) Completed 200 OK in 1ms (Views: 0.2ms | 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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 15:58:43.353678"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 15:58:43.353638"], ["updated_at", "2025-11-29 15:58:43.353638"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-29 15:58:43 +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_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", "objectives_completed", "tasks_completed") 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,\"submitted_flags\":[],\"flag_rewards_claimed\":[],\"pending_events\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-29 15:58:43.355891"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-29 15:58:43.355852"], ["updated_at", "2025-11-29 15:58:43.355852"], ["objectives_completed", 0], ["tasks_completed", 0]] 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-29 15:58:43 +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