Builtin Library
README.md
worldValidation
Cargo-check-style validation for a Zero world. Walks every script and
every asset under /source/ and reports problems in one structured
report. The world and its imported libraries are validated as cleanly
separated buckets so authoring problems in user content can be spotted
without being drowned out by issues in @builtin or any other
installed library — and vice versa.
The system is pure Luau on top of vfs.* and asset.*. It does not
spawn entities, allocate GPU resources, or mutate world state — the
report is read-only.
Two-bucket separation
/source/ ← user-authored content (this world)
foo.component/
main.scene/
libs/
@builtin/ ← imported library: @builtin
...
@mylib/ ← imported library: @mylib
...
Everything under /source/libs/<name>/ is treated as belonging to the
library <name>. Everything else under /source/ is world content.
Reports always carry the bucket split so a quick report.world.ok
check tells you whether YOUR code is clean independent of library
health.
Contents
validator.module/— orchestrator, public API entry point (check,validateWorld,validateLibraries,validateLibrary,filter,format,summary,saveReport,placeholders).scriptValidator.module/— per-file Luau script validation. Includes a placeholder syntax-check hook for the future when a runtime parser is available.assetValidator.module/— asset-folder validation. Delegates toasset.validate, the engine primitive theworld.pushgate runs, and maps its problems into the report — structure, content constraints, semantic hooks, and the private-subasset exemption all behave exactly as they do at publish time.vfsScanner.module/— recursive VFS scanner that enumerates scripts and asset roots under any path.reportFormatter.module/— filtering + formatting helpers (human,markdown,json,summary).tools/worldValidation.toolbox/— agent-callable surface:worldValidation.check— full validation pass.worldValidation.checkWorld— world bucket only.worldValidation.checkLibraries— every imported library.worldValidation.checkLibrary— one library by name.worldValidation.report— generate a report with filtering / formatting options; can write to a file.worldValidation.summary— one-line health summary.
Portability
The package's library modules use the ~ package-relative require
form — drop the package under another library, rename the parent
directory, or install it into a world under a different identity
and every internal lookup keeps resolving. The package is also
self-contained: no file outside worldValidation.package/ is
needed for the validator to run.
The toolbox at tools/worldValidation.toolbox/ is the one
exception: code-mode tools are mounted under the synthetic
@<lib>::tools.<ns> namespace, which has no .package ancestor
in its chunkname, so ~ can't walk back to a package alias from
a tool source. Tools therefore use the absolute
@builtin::systems.worldValidation.validator form to reach the
validator module, matching the pattern other package-shipped
toolboxes (characterController, volumeProbe) already follow.
Asset validation goes through asset.validate, which resolves each
asset's registered type (built-in or world-authored) and its
type.yaml from the live registry — the validator hardcodes no VFS
paths.
Quick start
local V = require("@builtin::~worldValidation.validator")
-- Full validation
local report = V.check()
if report.ok then
print("clean")
else
print(V.format(report, "human"))
end
-- World only, errors only, saved as markdown
local r = V.validateWorld({ severity = "error" })
V.saveReport(r, "/source/.validation/report.md", { format = "markdown" })
From an agent / tools:
tools.call("worldValidation.check", {})
tools.call("worldValidation.report", {
scope = "world",
severity = "error",
format = "markdown",
savePath = "/source/.validation/report.md",
})
tools.call("worldValidation.summary", {})
Problem schema
Every issue surfaced by the validator follows the same shape:
{
severity = "error" | "warning" | "info",
category = "structure" | "syntax" | "semantic" | "reference"
| "schema" | "placeholder",
code = "<short.code>", -- e.g. "structure.missing_required_file"
path = "<vfs path>", -- where the problem lives
message = "<details>", -- one-line human reason
source = "world" | "library:<name>",
placeholder = boolean, -- true if produced by a placeholder check
}
What's actually validated
| Layer | Implementation | Covers |
|---|---|---|
| Luau code | lsp.check(path) per script — the engine's embedded LSP | parser errors, type errors, every registered lint, including diagnostics inside asset folders (component / module / scene init.luau, etc.). |
| Asset folders | asset.validate per asset — the same primitive the world.push gate runs | missing required files / one_of_group alternatives (error), content constraints like an empty README or tag-less .metadata (error), unexpected entries when allow_unlisted: false (warning — the publish gate doesn't block on them), the type's own semantic validate hook, unknown/unresolved types (warning). Private subassets (a bundle's interior meshes / materials) are exempt from the describe-this-asset requirements, exactly as at publish time. |
Notes
- The validator is read-only. It never writes to
/source/except whensaveReportis invoked with an explicit destination path. - Validation is single-frame, synchronous — no
awaitboundaries. - Hot reload: editing this package's modules reloads them on next require. Running validation again picks up the new logic.