roblox-testing — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited roblox-testing (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Official sources (always check these for the latest):
This skill is about finding and fixing problems, not just writing code. It focuses on the tools and habits that separate working experiences from broken ones.
Activate when:
Cross-reference:
Use print, warn, and error deliberately:
print for normal diagnostics.warn for recoverable problems you should notice.error for programming errors that should stop execution.Include context in log messages:
warn(string.format("[DataStore] Save failed for %d: %s", userId, tostring(err)))Avoid logging secrets, player data, or PII.
Wrap fallible calls, especially cloud services, HTTP, DataStores, Marketplace:
local ok, result = pcall(function()
return someService:DoSomething()
end)
if not ok then
warn("DoSomething failed:", result)
endUse assert for internal invariants that should never fail:
assert(config.MaxSpeed > 0, "MaxSpeed must be positive")Open with F9 in-game or in Studio play mode.
Tabs:
Toggle Client/Server views to see which side emitted output.
The standard Roblox testing framework is TestEZ. It supports nested describe/it blocks, lifecycle hooks, async tests, and a rich matcher API.
TestEZ example:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TestEZ = require(ReplicatedStorage.DevPackages.TestEZ)
local MathUtils = require(ReplicatedStorage.MathUtils)
describe("MathUtils", function()
it("clamps values", function()
expect(MathUtils.clamp(5, 0, 10)).to.equal(5)
expect(MathUtils.clamp(-1, 0, 10)).to.equal(0)
expect(MathUtils.clamp(11, 0, 10)).to.equal(10)
end)
end)
TestEZ.TestBootstrap:run({ game.ReplicatedStorage.Tests })For legacy in-Studio tests, TestService:Error(msg) can mark failures visibly in Studio output, but most projects should prefer TestEZ. The scripts folder contains a minimal TestRunner.lua shim only for environments where TestEZ is unavailable.
Use the Luau language server (luau-lsp) or the Luau type checker in Studio to catch errors before runtime.
Best practices:
luau-lsp analyze in CI or before committing.--!strict for new modules.Use Studio's built-in debugger for step-through debugging:
Use xpcall with debug.traceback to capture full stack traces from failures:
local ok, err = xpcall(function()
riskyOperation()
end, debug.traceback)
if not ok then
warn(err)
endThis is especially useful at top-level entry points, scheduled callbacks, and connection handlers where pcall alone discards the stack.
Leaked RBXScriptConnection objects are a common source of memory leaks and stale state. Prefer explicit cleanup patterns:
local Maid = require(path.to.Maid)
local maid = Maid.new()
maid:GiveTask(workspace.ChildAdded:Connect(onChild))
maid:GiveTask(RunService.Heartbeat:Connect(onStep))
maid:Destroy() -- disconnects everything:Once() for one-shot event handlers.Instance.Destroying to trigger cleanup when an instance is removed:obj.Destroying:Connect(function()
cleanup()
end):Connect() with a matching :Disconnect() or destruction.The task library is more predictable than legacy spawn, delay, and wait:
-- good
task.wait(1)
task.delay(1, callback)
task.spawn(coroutineOrFn)
-- avoid
spawn(callback)
delay(1, callback)
wait(1)task.defer is useful for yielding to the next resumption cycle without opening a new thread.
local function sanitize(value)
if typeof(value) == "Instance" and value:IsA("Player") then
return "Player(" .. tostring(value.UserId) .. ")"
end
return value
endlocal lastLog = 0
local function throttledLog(message)
local now = os.clock()
if now - lastLog > 5 then
lastLog = now
warn(message)
end
endIncorrect network ownership causes jittery physics and replication lag. Visualize ownership and assign it explicitly:
-- Server
part:SetNetworkOwner(player)
-- Client-side visualization (debug only)
local ownershipLabel -- create BillboardGui or use DebugDrawUse BasePart:GetNetworkOwner() to inspect ownership. Vehicles and held items should usually be owned by the controlling player.
Wrap DataStore calls with exponential backoff and jitter:
local function dataStoreWithRetry(fn, maxAttempts)
maxAttempts = maxAttempts or 5
for attempt = 1, maxAttempts do
local ok, result = pcall(fn)
if ok then
return true, result
elseif attempt == maxAttempts then
return false, result
else
warn("DataStore attempt " .. attempt .. " failed; retrying...")
task.wait(2 ^ attempt * 0.1 + math.random() * 0.5)
end
end
endAlways call DataStores from the server and validate serialization before saving.
Use the Developer Console Memory tab or Scene Analysis to compare snapshots:
Open with Ctrl+F6 (⌘+F6) in Studio or the desktop client.
Use it to:
debug.profilebegin/debug.profileend.Key colors:
Available in Studio under Window → Performance Summary → Scene Analysis.
Views:
Scene Analysis is a Studio UI tool; there is no public SceneAnalysisService API.
Records CPU time per script. Use it when MicroProfiler points to scripts but you need to know which script.
| Symptom | Likely causes |
|---|---|
| Script silently fails | Missing pcall, error swallowed, wrong script context |
| Data not saving | DataStore called from client, non-serializable value, no pcall |
| Remote not working | Wrong side, handler not connected, argument mismatch |
| Lag spikes | Pathfinding every frame, too many particles, unbatched loops |
| Physics jitter | Wrong network ownership, assembly splits, conflicting constraints |
| NPCs stuck | Blocked path not recomputed, bad agent params, streaming issues |
| UI doesn't update | Property not replicated, wrong parent, layout order |
| Memory grows forever | Leaked connections, unparented instances, cached assets |
Shift+F3 in-game for network debug stats.Alt+S).Measure load time:
local start = os.clock()
game.Loaded:Connect(function()
print("Loaded in", os.clock() - start)
end)Enable Print Join Size Breakdown in Studio Settings → Network to see the largest replicated instances.
scripts/TestRunner.lua — a minimal TestEZ fallback with nested suites, lifecycle hooks, matchers, async support, and TestService integration.scripts/Logger.lua — a structured logger with level filtering and guarded formatting.scripts/DebugDraw.lua — utility for drawing rays, points, and boxes in 3D for visual debugging.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.