Conformance corpus (Phase 5) #
A second differential corpus: roblox-ts's own upstream test sources, compiled
by the real rbxtsc 3.0.0 into committed goldens that rotor's output is
byte-compared against (internal/conformance). Phase 5 now has three harnesses:
TestDiagnosticsCorpuscompiles the vendoredexcluded/diagnostics/*files one by one and asserts rotor's diagnostic IDs.TestConformancecompiles enabled golden fixtures one by one through temp projects rooted underproject/, so unsupported nodes in unrelated upstream specs do not block the fixtures that already match.TestBehavioralSuiteandTestRandomnessAcceptanceare environment-gated runners for the upstream runtime suite and the realrandomnessproject.
Provenance #
Sources copied verbatim from the vendored upstream checkout at
reference/roblox-ts/tests/src — roblox-ts v3.0.0, commit
d1d5486094ac1d1821b7eb03ce0de0890d30b82e (see reference/VERSIONS.md).
Upstream tests/src contains 131 files, all accounted for:
| Destination | Files | What |
|---|---|---|
project/src/ |
45 | main.server.ts, services.d.ts, helpers/** (5), tests/** (38 spec files, ~5.8k LOC of feature coverage) |
excluded/diagnostics/ |
86 | the entire upstream diagnostics/ directory (85 .ts/.tsx + its README.md) |
| Goldens | 44 | every project/src file except services.d.ts (declaration file, emits nothing) |
Exclusions #
excluded/diagnostics/**(85 sources): these files intentionally fail compilation — upstream's test driver (src/CLI/test.ts) compiles each one individually and asserts that the expected diagnostic is produced. They can never be part of a clean-compile golden corpus. They are kept here (not dropped) so a future diagnostics-conformance harness can use them.
No other file failed: all 44 emitting sources compile clean under the setup below, on the first full run.
Fixture project recipe (project/) #
package.json— exact pins, reconciled betweentestdata/diff/projectand upstreamtests/package.json:roblox-ts@3.0.0,typescript@5.5.3,@rbxts/compiler-types@3.0.0-types.0,@rbxts/types@^1.0.800(same as the diff project),- plus the upstream test deps as npm pins:
@rbxts/roact@1.4.4-ts.0,@rbxts/services@1.5.3,@rbxts/testez@0.4.2-ts.0(upstream declares the first viagithub:roblox-ts/rbx-roact; its lockfile resolved the same 1.4.4-ts.0, which also exists on npm). - Upstream's lockfile had stale
@rbxts/compiler-types@2.2.0-types.0and@rbxts/types@1.0.751; we use the 3.0.0-matching compiler-types and a newer types floor, identical to the diff corpus. Goldens were generated with@rbxts/types@1.0.925installed;project/package-lock.jsonis committed (like the diff project's) so installs are reproducible.
tsconfig.json— upstreamtests/tsconfig.jsonverbatim (minus comments) plus"include": ["src"]. Differences from the diff project's tsconfig:jsxFactoryisRoact.jsx(notReact.createElement),baseUrl: "src"is set, andincremental/tsBuildInfoFileare omitted.default.project.json— model-type, same shape as the diff project's. Upstream uses a full DataModel (game) project that placeshelpers/rojo/isolated.tsin StarterGui; under a model project nothing is isolated, and all files (including that one) still compile clean. The diagnostics harness keeps this model project for the portable fixtures, but stages the two Rojo-topology diagnostics in a temporary upstream-shaped DataModel project so their original isolation / missing-$path expectations are still exercised.rbxtscis invoked with--allowCommentDirectivesbecause the upstream sources use@ts-ignore/@ts-expect-error; upstream's own test driver setsallowCommentDirectives: truefor the same reason. Rotor now honors the same option in its project/build path, so this corpus stays aligned with the upstream driver behavior.
Regenerating goldens #
powershell -File tools/oracle/conformance-oracle.ps1
(Requires Node plus Bun or npm — mise-managed; the script invokes
node .\node_modules\roblox-ts\out\CLI\cli.js directly so Bun/npm installs behave the same. It
prefers bun install --no-save on first run, falls back to npm, cleans project/out/, compiles, and mirrors
out/**/*.luau into golden/ preserving subdirectories.)
Enabling fixtures #
Add the golden-relative slash path (e.g. "tests/array.spec.luau") to
EnabledFixtures in internal/conformance/manifest.go. Then
go test ./internal/conformance/ -run TestConformance -count=1 -v compiles
each enabled fixture through a temp project rooted under project/, preserving
the shared node_modules tree while limiting the compile to the selected
source plus shared helpers.
As of June 7, 2026, 44 / 44 committed goldens are enabled. DisabledFixtures
is empty and the vendored conformance corpus is fully closed: byte-diff,
diagnostics, runtime, and real-project acceptance all have green harnesses.
Diagnostics corpus #
Run:
go test ./internal/conformance/ -run TestDiagnosticsCorpus -count=1
The harness installs project/node_modules on first use if needed, then
overlays each vendored diagnostics fixture under project/src/__diagnostics
and compiles it through the real conformance project config. The two
Rojo-topology fixtures (noRojoData.ts, noIsolatedImport.ts) are staged in
temporary projects that copy the upstream tests/default.project.json, so the
full vendored diagnostics corpus now runs without skips.
Runtime suite #
Run:
go test ./internal/conformance/ -run TestBehavioralSuite -count=1 -v
Requires rojo plus lune. Detection order is:
ROTOR_ROJO_PATH/ROTOR_LUNE_PATH- the executable on
PATH
The test skips with an actionable message if either tool is missing. When available it stages a temporary runtime subset project containing:
- the current enabled conformance specs,
- shared helpers and entrypoints,
- an upstream-shaped DataModel Rojo config for
ServerScriptService.tests.
This keeps the runtime run aligned with the upstream TestEZ corpus while still staging the temporary project topology that Lune needs.
When the tools are available it:
- builds a staged conformance subset project with
rotor, - runs
rojo buildto produce a place file, - executes the upstream
reference/roblox-ts/tests/runTestsWithLune.lua.
With rojo + lune available, the staged suite now executes the full vendored
runtime corpus green (460 passed, 0 failed, 0 skipped on June 7, 2026).
randomness acceptance #
Run:
go test ./internal/conformance/ -run TestRandomnessAcceptance -count=1 -v
Set ROTOR_RANDOMNESS_PATH to the local project root before running. The test
accepts either the project root or a direct path to its tsconfig.json. It
skips with an explicit setup message when unset and otherwise:
- copies the target project twice,
- runs Rotor's full build pipeline over one copy,
- runs the local
rbxtscinstall over the other copy, - compares the normalized
out/andinclude/trees byte-for-byte.
This keeps the harness environment-gated while making it a real build/output
acceptance proof rather than a compile-only smoke test. With a local
randomness checkout available, the staged compare is green byte-for-byte on
both out/ and include/.