1
0
This repository has been archived on 2026-08-25. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
tera/src/test/integration/barrel.test.ts
T
karti db074e9cf7 feat: tone-mapped render rig, studio devices, LA fidelity pass, UI overhaul
The build the studios needed, across eight workstreams and one strict file
partition.

**The render rig was the quality ceiling.** The renderer ran three's
NoToneMapping default while atmosphere drove the sun to 2.35 and assets set
emissives to 3.2, so every value above 1.0 hard-clipped to flat white — which is
why walls blew out and every fitting looked like a white rectangle. ACES filmic
tone mapping and an explicit output colour space land in `stage.ts`, and the
atmosphere intensity table and palette headroom are re-tuned against the new
curve rather than left tuned for the clipping we removed.

`engine/environmentRig.ts` builds a PMREM environment at runtime, procedurally,
so nothing binary is committed. There was no environment map anywhere before, so
every `metalness > 0` role had nothing to reflect and rendered dull grey — a
defect the code already documented against itself in `office/optimus.ts`, where a
whole material role was abandoned over it, and worked around in `modelX.ts` with
a fake emissive that this change deletes. Atmosphere remains the sole light
owner; the rig derives from the `LightingState` it already produced.

**Studio hardware exists.** There was no device concept anywhere in the product:
no type, no route, no state. `devices/types.ts` fixes a declaration/state/
capability/command contract that a smart light, a thermostat, a door sensor and a
charger all fit without a schema change, and both studios now carry a desk mic
and a computer speaker with deterministic simulated behaviour behind an adapter
seam a real API can occupy later. Reads are the demo and are open; commands are a
signed-in action and are kept off the read body entirely, because a shared cache
replaying a GET that turned a microphone on is exactly what the fail-closed
cache default exists to prevent.

**The ADS-B licence hole is closed.** `TERA_ADSB_ENDPOINT` accepted any URL, the
response was served publicly cacheable, and the attribution hardcoded adsb.lol
regardless of where the endpoint pointed — one env var away from republishing
non-redistributable data under an open-terms credit. The host is now allowlisted,
the credit is derived from the host actually configured, public cacheability is
conditional on redistributability, and a refused endpoint demotes to simulated
flights and says so in `degraded[]`. The gate is on the source, not the feature:
live aircraft and their detail cards stay open to anonymous visitors.

**The LA studio was never the smaller pack** — 16 rooms and 248 props against
SF's 4 and 28. Its deficit was fidelity per square metre: 98 of those props were
ceiling troffers, it bound no props to seats, placed none of the habitat kit, and
12 of its 16 rooms had no viewpoint. Density comes from new asset kinds rather
than more instances, because `furnish.ts` draws once per kind and folds colour
into the batch key, so repeat instances add nothing the eye can read.

**The interface stops being forty imperative mutations.** Every visibility
decision moves into a pure, tested `ui/chromeState.ts` and one applier, so the
chrome has coverage for the first time. Deleted: ~100 lines of CSS and two
bindings targeting elements that no longer exist, and a `body:has()` rule that
shifted the desktop layout by 160px for touch controls hidden there. Fixed: the
office picker tabs that drew their label and their badge on top of each other.
Added: a first-run flow, because the product is two verbs and neither was ever
stated on screen. Mobile is designed on its own terms instead of being the
desktop with things hidden — the plan view comes back, and the keyboard-only
shortcuts button is replaced by touch controls.

`arena/studioOps.ts` frames the whole thing as the multi-variable environment it
is, wrapping the same simulators the renderer drives rather than a headless copy.

Also removed `input/vehicle.ts`, which nothing but its own test imported.

Tests 385 -> 961, all passing. Typecheck, build, performance budgets across six
matrix cells, no-binaries, provenance, dependency licences, zero-config boot and
arena source hashes all green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 19:44:24 -07:00

139 lines
5.5 KiB
TypeScript

/**
* The public package surface, and the one promise it makes.
*
* `src/index.ts` is what `package.json`'s `"."` export points at, so it is the
* thing a verifier, a training harness or a Node service `import`s. The promise
* is that everything reachable from it runs **with no renderer, no DOM and no
* network** — because the consumers who want the arena and the simulators are
* precisely the consumers who have none of the three.
*
* That is not a property you can assert by importing the file and seeing it
* work: `import * as THREE from "three"` succeeds perfectly well under Node and
* costs a consumer half a megabyte for nothing. So this walks the static import
* graph and reads it. A single `from "three"` anywhere in the closure fails,
* and names the file and the chain that reached it, which is the only form of
* this failure anybody can act on.
*/
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import test from "node:test";
import * as barrel from "../../index.ts";
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../..");
const ENTRY = path.join(ROOT, "src/index.ts");
/**
* Every relative specifier in a file, `import` and `export` alike.
*
* `export * from "./x.ts"` is the form the barrel itself is written in, and a
* matcher that only looked at `import` would walk none of it.
*/
const SPECIFIER = /(?:^|\n)\s*(?:import|export)\b[^;\n]*?from\s+["']([^"']+)["']/g;
/** `await import("./x.ts")`, which is how a renderer would sneak in lazily. */
const DYNAMIC = /\bimport\s*\(\s*["']([^"']+)["']\s*\)/g;
/** Walk the graph from `entry`, returning every file reached and how. */
function closure(entry: string): Map<string, string[]> {
const reached = new Map<string, string[]>([[entry, []]]);
const queue = [entry];
while (queue.length > 0) {
const file = queue.shift() as string;
const source = readFileSync(file, "utf8");
const chain = reached.get(file) ?? [];
for (const pattern of [SPECIFIER, DYNAMIC]) {
pattern.lastIndex = 0;
let match: RegExpExecArray | null;
while ((match = pattern.exec(source)) !== null) {
const specifier = match[1];
if (specifier === undefined || !specifier.startsWith(".")) continue;
const resolved = path.resolve(path.dirname(file), specifier);
if (reached.has(resolved)) continue;
reached.set(resolved, [...chain, path.relative(ROOT, file)]);
queue.push(resolved);
}
}
}
return reached;
}
/** Bare specifiers a module in the closure is allowed to depend on. */
const ALLOWED_PACKAGES = new Set<string>([]);
test("the barrel exports the renderer-independent surfaces this build added", () => {
for (const name of [
"ARENA_ENVIRONMENTS",
"flattenObservation",
"structureAction",
"observationWidth",
"rollout",
"createSimulatedDevices",
"createSimulatedVehicleTelemetry",
"normalizeDeviceCommand",
"normalizeVehicleTelemetryCommand",
"exteriorVehicleAppearance",
"DEVICE_RANGES",
"Plan",
]) {
assert.ok(
name in barrel,
`src/index.ts no longer exports ${name}; a consumer's import just broke`,
);
}
});
test("nothing reachable from the barrel imports three.js", () => {
const offenders: string[] = [];
for (const [file, chain] of closure(ENTRY)) {
const source = readFileSync(file, "utf8");
if (/from\s+["']three(?:\/|["'])/.test(source) || /import\s*\(\s*["']three/.test(source)) {
offenders.push(`${path.relative(ROOT, file)} (via ${chain.join(" → ") || "the barrel itself"})`);
}
}
assert.deepEqual(
offenders,
[],
"three.js is on the public package surface. The render layer for a simulation " +
"(interiors/devices.ts, engine/officeExterior.ts, interiors/officeScene.ts) is " +
"never exported; the state machine behind it is.",
);
});
test("nothing reachable from the barrel takes a bare dependency at all", () => {
const offenders: string[] = [];
for (const [file] of closure(ENTRY)) {
const source = readFileSync(file, "utf8");
for (const pattern of [SPECIFIER, DYNAMIC]) {
pattern.lastIndex = 0;
let match: RegExpExecArray | null;
while ((match = pattern.exec(source)) !== null) {
const specifier = match[1];
if (specifier === undefined) continue;
if (specifier.startsWith(".") || specifier.startsWith("node:")) continue;
if (ALLOWED_PACKAGES.has(specifier)) continue;
offenders.push(`${path.relative(ROOT, file)}${specifier}`);
}
}
}
assert.deepEqual(offenders, [], "an unvetted runtime dependency reached the package surface");
});
test("nothing reachable from the barrel reaches for a browser global", () => {
// Read as source rather than executed, because a `document` reference inside a
// branch nobody takes is still a module that cannot be loaded in a worker
// whose global object does not have one.
const globals = /\b(?:document|localStorage|sessionStorage|navigator|requestAnimationFrame)\b/;
const offenders: string[] = [];
for (const [file] of closure(ENTRY)) {
const source = readFileSync(file, "utf8")
// Comments talk about the DOM constantly and correctly; only code counts.
.replace(/\/\*[\s\S]*?\*\//g, "")
.replace(/(^|\n)\s*\/\/[^\n]*/g, "$1");
if (globals.test(source)) offenders.push(path.relative(ROOT, file));
}
assert.deepEqual(offenders, [], "a DOM global is reachable from the package surface");
});