From 18f649d7664b4cde574ca2ac36559cd152b1f363 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 10 Mar 2026 17:32:37 +0000 Subject: [PATCH] debug: add diagnostic logging to invention system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every failure path was silent — LLM nulls, parse failures, validation rejections, and promise errors were all swallowed. Adds per-attempt logging at each gate plus a periodic summary of NPC/inventory/item state. Co-Authored-By: Claude Opus 4.6 --- server/src/systems/inventionSystem.ts | 39 ++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/server/src/systems/inventionSystem.ts b/server/src/systems/inventionSystem.ts index 42fcf4e..775a8d6 100644 --- a/server/src/systems/inventionSystem.ts +++ b/server/src/systems/inventionSystem.ts @@ -26,6 +26,7 @@ export function createInventionSystem( // Track in-flight requests to avoid duplicates const pendingEntities = new Set(); const pendingItemIds = new Set(); + let lastDiagTick = 0; return { update(world: World, tick: number): void { @@ -39,6 +40,18 @@ export function createInventionSystem( const npcs = world.query('npcBrain'); + // Periodic diagnostic summary (every 1000 ticks ≈ 10 invention checks) + if (tick - lastDiagTick >= 1000) { + lastDiagTick = tick; + let withInventory = 0; + let emptyInventory = 0; + for (const eid of npcs) { + const i = world.getComponent>(eid, 'inventory'); + if (i && i.size > 0) withInventory++; else emptyInventory++; + } + console.log(`[Invention] tick=${tick} npcs=${npcs.length} withItems=${withInventory} emptyInv=${emptyInventory} pending=${pendingEntities.size} knownItems=${itemRegistry.getAll().length}`); + } + for (const entityId of npcs) { if (pendingEntities.has(entityId)) continue; @@ -85,6 +98,7 @@ export function createInventionSystem( : ''; pendingEntities.add(entityId); + console.log(`[Invention] eureka! npc=${name} (${entityId}) INT=${intelligence} CUR=${curiosity} chance=${(chance * 100).toFixed(2)}% items=${inv.size}`); llmService.generate('invention', { npcName: name, @@ -104,14 +118,28 @@ export function createInventionSystem( }).then(response => { pendingEntities.delete(entityId); + if (!response) { + console.log(`[Invention] LLM returned null for npc=${name} (${entityId})`); + return; + } + const parsed = parseInventionResponse(response); - if (!parsed) return; + if (!parsed) { + console.log(`[Invention] parse failed for npc=${name} (${entityId}), response=${response.substring(0, 200)}`); + return; + } const validation = validateInvention(parsed, itemRegistry); - if (!validation.valid) return; + if (!validation.valid) { + console.log(`[Invention] validation failed for npc=${name} (${entityId}): ${validation.error} (suggested: "${parsed.name}" cat=${parsed.category} inputs=${JSON.stringify(parsed.inputs)})`); + return; + } // Race guard: check if another NPC already claimed this itemId - if (pendingItemIds.has(validation.itemId!)) return; + if (pendingItemIds.has(validation.itemId!)) { + console.log(`[Invention] race guard blocked "${parsed.name}" for npc=${name} (${entityId}), itemId=${validation.itemId} already pending`); + return; + } pendingItemIds.add(validation.itemId!); // Compute current day @@ -120,6 +148,8 @@ export function createInventionSystem( const cycleTicks = Math.round(dayTicks + nightTicks); const day = Math.floor(tick / cycleTicks) + 1; + console.log(`[Invention] SUCCESS npc=${name} (${entityId}) invented "${parsed.name}" (${validation.itemId}) cat=${parsed.category}`); + registerInvention({ raw: parsed, itemId: validation.itemId!, @@ -165,7 +195,8 @@ export function createInventionSystem( }); pendingItemIds.delete(validation.itemId!); - }).catch(() => { + }).catch((err) => { + console.log(`[Invention] LLM error for npc=${name} (${entityId}): ${err?.message ?? err}`); pendingEntities.delete(entityId); }); }