$code Loading Issue Investigation #
Date: January 3, 2026
Status: In Progress
Symptom: $roz (cached KidLisp code) doesn't load from prompt, but pasting the same source code works fine.
Summary #
When entering $roz in the prompt, the piece never boots even though all the message passing appears to work correctly. The user remains stuck at the prompt.
Working Flow (Pasting Source Code) #
When pasting the actual KidLisp source code, everything works:
- Source passed to
load() lisp.module()compiles itdisk-loadedsent →loading-completereceived →hotSwap()runs- Next frame:
paintCount === 0n && loading === false→ boot() runs - Piece displays correctly
Broken Flow ($roz) #
When entering $roz:
- ✅
getCachedCodeMultiLevel("roz")fetches the source (239 chars) - ✅
lisp.module()compiles it successfully - ✅
disk-loadedsent to bios - ✅
loading-completesent back to disk - ✅
hotSwap()runs:paintCountreset from 497 to0nloadingset tofalsebootedset tofalse
- ❌ Boot never runs - no frames show
paintCount=0nafter hotSwap
Console Log Analysis #
// Before loading-complete arrives:
🔍 DISK: Boot check - paintCount=496, loading=true, booted=true
// loading-complete arrives and hotSwap runs:
🔍 DISK: Received loading-complete, hotSwap exists? true
🔍 DISK hotSwap: Starting, loadedModule exists? true, has boot? true, has paint? true
🔍 DISK hotSwap: Resetting paintCount from 497 to 0n
🔍 DISK: hotSwap called, loading = false
// AFTER this point - NO MORE FRAME LOGS APPEAR
// The boot check should show: paintCount=0n, loading=false, booted=false
// But we never see it!
Key Observation #
After hotSwap() completes, frame messages continue (render loop is still running), but:
- No
🔍 DISK FRAME:logs appear (added forpaintCount < 3n) - No
🔍 DISK: Boot checklogs appear
This suggests either:
- Frames aren't reaching the disk worker after hotSwap
- Something is blocking/returning early in frame processing
- The frame handler is stuck or erroring silently
Relevant Code Locations #
- disk.mjs load(): Lines 6442+ - loads cached codes via
getCachedCodeMultiLevel() - disk.mjs hotSwap(): Line 7861 - resets state after loading-complete
- disk.mjs frame handler: Line 9961 - processes frames, runs boot check
- disk.mjs boot check: Line 11479 -
if (paintCount === 0n && loading === false) - bios.mjs receivedChange(): Line 3918 - receives messages from worker
- bios.mjs loading-complete: Line 11462 - sends loading-complete to disk
Debug Logs Added #
-
disk.mjs frame handler (line 9961):
if (paintCount < 3n) { console.log(`🔍 DISK FRAME: paintCount=${paintCount}, loading=${loading}, booted=${booted}, needsRender=${content.needsRender}`); } -
disk.mjs boot check (line 11479):
console.log(`🔍 DISK: Boot check - paintCount=${paintCount}, loading=${loading}, booted=${booted}`); -
bios.mjs onMessage (line 3363):
if (m?.data?.type && m.data.type !== "frame") { console.log(`🔍 BIOS onMessage: type="${m.data.type}"`); }
Theories #
Theory 1: Frame messages blocked after hotSwap #
Something in the hotSwap or immediately after might be blocking frame processing.
Theory 2: Worker message queue issue #
The worker might have messages queued that interfere with the new piece's frame handling.
Theory 3: State not properly reset #
Some state variable might not be properly reset, causing frames to be ignored.
Theory 4: Race condition with boot-file setTimeout #
The boot-file handler uses setTimeout to defer tokenizer work. This setTimeout executes AFTER hotSwap completes, which might cause interference:
🔍 BIOS: boot-file setTimeout executing for "aesthetic.computer/disks/$roz"
Next Steps #
- Add more logging at the very start of frame handler (before any checks)
- Check if frames are being sent by bios but not received by disk
- Investigate if there's an error being swallowed
- Check if the GOL transition system is interfering
- Verify that the worker isn't stuck in some loop
Files Modified During Investigation #
/workspaces/aesthetic-computer/system/public/aesthetic.computer/lib/disk.mjs- Added error catching wrapper around
makeFrame(e)in onmessage handler - Added logging at makeFrame entry point for all messages when
paintCount < 5n - Added logging in frame handler when
paintCount < 5n - Added logging in
loading-completehandler before/after hotSwap
- Added error catching wrapper around
/workspaces/aesthetic-computer/system/public/aesthetic.computer/bios.mjs
Diagnostic Changes (2026-01-03) #
Added the following debug logging to trace the issue:
-
onmessage wrapper - Catches any swallowed async errors:
makeFrame(e).catch(err => { console.error("🛑 DISK makeFrame error:", err, "| type:", e.data?.type); }); -
makeFrame entry - Logs all non-beat messages when paintCount < 5n:
if (paintCount < 5n && type !== "beat") { console.log(`🔍 DISK makeFrame: type="${type}", paintCount=${paintCount}`); } -
Frame handler - Logs frame state:
if (paintCount < 5n) { console.log(`🔍 DISK FRAME: paintCount=${paintCount}, loading=${loading}, booted=${booted}`); } -
loading-complete handler - Logs state before/after hotSwap:
console.log("🔍 DISK: Received loading-complete, paintCount=", paintCount, ...); console.log("🔍 DISK: After hotSwap, paintCount=", paintCount, ...);