Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit65083fe8f2

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 to asset.validate, the engine primitive the world.push gate 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

LayerImplementationCovers
Luau codelsp.check(path) per script — the engine's embedded LSPparser errors, type errors, every registered lint, including diagnostics inside asset folders (component / module / scene init.luau, etc.).
Asset foldersasset.validate per asset — the same primitive the world.push gate runsmissing 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 when saveReport is invoked with an explicit destination path.
  • Validation is single-frame, synchronous — no await boundaries.
  • Hot reload: editing this package's modules reloads them on next require. Running validation again picks up the new logic.