diff --git a/docs/REMEDIATION_PLAN.md b/docs/REMEDIATION_PLAN.md
index 12a60fd..6257a7b 100644
--- a/docs/REMEDIATION_PLAN.md
+++ b/docs/REMEDIATION_PLAN.md
@@ -45,8 +45,8 @@ Key: `S` ≤ half day · `M` ~1–3 days · `L` ~1 week+ · 🔴 launch-blocker
## Phase 4 — De-spaghetti / structural cleanup (🟡)
- [x] **4.1 L — Break up `index.js` (substantially).** ✅ Extracted the verify HTML → `views/verifyPage.js` (now HTML-escaped), all 15 admin endpoints → `routes/admin.js`, and the 3 smirk endpoints → `routes/auth.js`, each as DI factories with smoke tests. **index.js: 2029 → 882 lines (-57%).** _Remaining user/public routes left inline — they're interleaved with bootstrap and have no route tests, so further slicing is diminishing-return/higher-risk; the structure + pattern are established for later._
- [~] **4.2 M — Kill duplicates (partial).** ✅ Deleted the dead `handlePlayerMove` handler (a footgun that double-stepped the monster + bypassed escape/collision detection) and its orphaned `playerMoveTimestamps` map/cleanup — the live path is `MovementManager`. _Remaining (lower-value/higher-effort): merge `rpcService`+`rpccalls`, unify `payout_address` column widths, address the `QueryValidator` false-positive — deferred._
-- [ ] **4.3 M — Config as immutable snapshots;** stop mutating `process.env` (`gameModeManager.js:189`).
-- [ ] **4.4 M — Frontend de-spaghetti.** Shared `escapeHtml`/`dom.js`; kill double-declares + dead `_appendMessage`; explicit init ordering; upgrade/drop jQuery; gate broadcast logging (`broadcastManager.js:33`).
+- [⏸] **4.3 M — Config snapshots — DEFERRED (risk > value).** The `process.env` config write-back is ugly but **load-bearing**: it's how DB-persisted hot-reload config reaches the env-based readers — `difficultyConfig` selects the difficulty preset from `process.env.GAME_MODE`, and `debugManager`'s simulated-blocks **safety gate** reads it. A proper `ConfigService` means rewiring those sensitive readers; with no config-reload tests and zero correctness/safety upside, the risk isn't justified right now. Documented rather than rewritten.
+- [~] **4.4 M — Frontend de-spaghetti (safe wins done).** ✅ Shared `escapeHtml` already added in 0.6. Removed the duplicate `_gameMode` declaration (the later `null` silently shadowed the earlier `'free'`). Removed the dead `SocketHandlers._appendMessage` calls in `smirkAuth.js` (the method never existed; always fell through to the working `.text()` append). Gated `broadcastManager`'s high-volume per-event logs (user-count, chat-message-with-PII, game-update, game-start) behind debug mode. _Deferred: jQuery 3.4.1 upgrade and the nested-`setTimeout` init-ordering rewrite (larger, no frontend tests, higher risk)._
- [x] **4.5 S — Delete stale `test/` scratch files.** ✅ Removed 14 non-jest leftovers (5 `.js` scratch scripts + 9 `.html` debug pages) — confirmed they contained no jest constructs and were referenced nowhere. `test/` is now exclusively the 21 real jest suites.
## Phase 5 — Test & ops overhaul (🟠 — the launch gate)
diff --git a/html/js/network/smirkAuth.js b/html/js/network/smirkAuth.js
index 0ef780a..04be1ba 100644
--- a/html/js/network/smirkAuth.js
+++ b/html/js/network/smirkAuth.js
@@ -214,11 +214,8 @@ const SmirkAuth = {
? 'Smirk wallet connected! Payout address set.'
: 'Smirk wallet authenticated! Please set your payout address manually.';
- if (typeof SocketHandlers !== 'undefined' && SocketHandlers._appendMessage) {
- SocketHandlers._appendMessage('status', successMsg);
- } else {
- $('#messages').append($('
').text(successMsg));
- }
+ // .text() sets textContent, so the message is safe from injection.
+ $('#messages').append($('').text(successMsg));
// Update address button status if available
if (typeof SocketHandlers !== 'undefined' && SocketHandlers._updateAddressButtonStatus) {
@@ -233,11 +230,7 @@ const SmirkAuth = {
// Show error message
const errorMsg = 'Smirk login failed: ' + err.message;
- if (typeof SocketHandlers !== 'undefined' && SocketHandlers._appendMessage) {
- SocketHandlers._appendMessage('error', errorMsg);
- } else {
- $('#messages').append($('').text(errorMsg));
- }
+ $('#messages').append($('').text(errorMsg));
throw err;
}
diff --git a/html/js/network/socketHandlers.js b/html/js/network/socketHandlers.js
index 6299630..8677666 100644
--- a/html/js/network/socketHandlers.js
+++ b/html/js/network/socketHandlers.js
@@ -13,7 +13,8 @@ const SocketHandlers = {
_hasPayoutAddress: false,
_creditsBalance: 0,
- _gameMode: 'free',
+ _gameMode: null, // set from the server's game-modes event; was previously declared
+ // twice in this object literal (the later `null` silently won)
_directPayoutsEnabled: false,
_paymentsEnabled: false,
@@ -1394,8 +1395,7 @@ const SocketHandlers = {
// =====================
// Early Entry Functions
// =====================
-
- _gameMode: null,
+
_earlyEntryConfig: { enabled: false },
_isQueued: false,
diff --git a/src/network/broadcastManager.js b/src/network/broadcastManager.js
index 94e7ec3..bf46a31 100644
--- a/src/network/broadcastManager.js
+++ b/src/network/broadcastManager.js
@@ -30,8 +30,10 @@ class BroadcastManager {
count = this.io.engine.clientsCount || 0;
}
- console.log(`👥 Broadcasting user count: ${count} (last was ${this._lastUserCount})`);
-
+ if (this.debugManager?.CONSOLE_LOGGING) {
+ console.log(`👥 Broadcasting user count: ${count} (last was ${this._lastUserCount})`);
+ }
+
// Always broadcast to ensure new clients get the count
this._lastUserCount = count;
this.io.emit('user_count', { count });
@@ -60,8 +62,10 @@ class BroadcastManager {
* @param {string} socketId - Socket ID of the sender
*/
broadcastChatMessage(username, message, timestamp, socketId) {
- console.log(`💬 Broadcasting chat message from ${socketId}: "${message}"`);
-
+ if (this.debugManager?.CONSOLE_LOGGING) {
+ console.log(`💬 Broadcasting chat message from ${socketId}: "${message}"`);
+ }
+
this.io.emit('chat_broadcast', {
username: username,
message: message,
@@ -100,11 +104,12 @@ class BroadcastManager {
* @param {object} gameState - The game state to broadcast
*/
sendGameUpdate(playerSocketId, gameState) {
- // Debug logging for lighting data in updates
- console.log(`📡 sendGameUpdate to ${playerSocketId}:`);
- console.log(` - Lighting data: ${!!gameState.lighting} (${gameState.lighting ? Object.keys(gameState.lighting).length : 0} rows)`);
- console.log(` - Torch data: ${!!gameState.torches} (${gameState.torches ? gameState.torches.length : 0} torches)`);
-
+ if (this.debugManager?.CONSOLE_LOGGING) {
+ console.log(`📡 sendGameUpdate to ${playerSocketId}:`);
+ console.log(` - Lighting data: ${!!gameState.lighting} (${gameState.lighting ? Object.keys(gameState.lighting).length : 0} rows)`);
+ console.log(` - Torch data: ${!!gameState.torches} (${gameState.torches ? gameState.torches.length : 0} torches)`);
+ }
+
// Send to the player
this.io.to(playerSocketId).emit('game_update', gameState);
@@ -125,7 +130,9 @@ class BroadcastManager {
* @param {object} gameState - Initial game state
*/
sendGameStart(socketId, gameState) {
- console.log(`🎮 SENDING GAME_START to ${socketId}`);
+ if (this.debugManager?.CONSOLE_LOGGING) {
+ console.log(`🎮 SENDING GAME_START to ${socketId}`);
+ }
this.io.to(socketId).emit('game_start', gameState);
}