Short but important day. Yesterday’s production test surfaced more issues than just the race condition.

The bugs

Duplicate script execution — Scripts were running twice in published games. This is a classic Roblox gotcha: if a Script is inside a Model that gets cloned or reparented, the script can restart. The engine sees the parent change as a new context and fires the script again. We were seeing double-initialization of assets, double-scoring, double everything.

The fix was a re-entry guard at the top of every managed script:

if _G.__initialized_myAsset then return end
_G.__initialized_myAsset = true

Not elegant, but effective. Later (Day 5) we’d solve this properly with the boot system.

Backpack ChildAdded firing on destroyed items — When a player dies in Roblox, their character is destroyed and recreated. Tools in the backpack get destroyed along with it. Our ChildAdded listener was picking up transient items during respawn and trying to initialize them, only for them to be immediately garbage collected.

The subtle part: ChildAdded fires even for children that are about to be destroyed. There’s no built-in way to distinguish “this item was just added intentionally” from “this item is a ghost from a dying character.” We added a deferred check — wait one frame, then verify item:IsDescendantOf(game) before processing.

Destroyed instance references — Related to the above. In Roblox, calling :Destroy() on an Instance doesn’t set your Lua reference to nil. The variable still points to the instance, but accessing any property throws an error. This trips up a lot of developers:

local part = workspace.SomePart
part:Destroy()
print(part)         -- still a valid reference
print(part.Name)    -- ERROR: "The Parent property of Part is locked"

We were hitting this in the notification system when it tried to update text on a destroyed GUI element. The fix was nil-checking the reference’s parent before any property access.

New feature: MessageTicker

Built a client-side notification system. It shows temporary messages that scroll in from the side — “Round starting!”, “New high score!”, that sort of thing. Messages queue up and display sequentially, each one visible for a configurable duration before sliding out.

Originally called ClientMessage, we renamed it to MessageTicker twenty-five minutes later. Record time for regretting a name choice. The original name was too generic — it sounded like a RemoteEvent wrapper, not a UI notification system.