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/scripts/look.mjs
T
karti 285b5b19e7 fix: the merged board's live feeds, and two instruments it could not be judged without
An ultracode investigation mapped the single-board work across five parallel
readers and three adversarial reviewers. It found things this session would have
walked into, and two of them are fixed here.

**THE MERGED BOARD WAS SHIPPING WITH THREE FEEDS SILENTLY OFF.** Live ADS-B and
live weather were gated on `id !== "california"` — "not the coarse statewide
board", correct the day it was written, since live aircraft over a board at
1,919 m to the unit are a glyph problem and one station cannot speak for a
thousand kilometres of coast. `cities/unify.ts` then built a board that is the
whole state AND metro-detailed, keeping the `california` id deliberately so the
fire gate, the ladder's region table and every `?city=` deep link keep working.
It inherited a gate meant for something else. Measured before the fix: the
`#source` badge read `""` on the merged board and `live weather · live traffic`
on the Bay Area's. A defect that reads as "it feels less alive" and never as an
error.

`carriesMetroDetail(city)` asks the pack instead: `focusRegions` is the honest
predicate and needs no new field, because the coarse state pack declares none
and every pack with ground worth drawing at metro resolution declares one.

**AND ASKING WAS NOT ENOUGH, BECAUSE THE FEEDS ARE PER-METRO.** With the gate
fixed the board asked — and was refused: `GET /flights?lat=37.30&lng=-119.25&
radiusNm=402 → 400 bad_request, "Nothing this deployment serves is near
37.3,-119.25"`. Correctly: `regionOf` derives its circle from the board's bounds,
which on a statewide board is 402 nautical miles centred on the middle of the
state, and what the deployment serves is San Francisco and the Southland, five
hundred and sixty kilometres apart.

`mergedTraffic` asks for both. In `adapters/http.ts` and not `engine/flights.ts`
for the reason `TrafficSource` itself lives there: the engine draws darts at
coordinates and has no business with provenance, and every interesting part of
this merge is provenance. De-duplicated by id, because overlapping circles both
see the aircraft between them and `flights.ts` measures a track's span from
repeated observations — a duplicate is not merely a double image. `live()` is
`some` and not `every`, so one dark metro does not make the other's observed
traffic claim to be simulated. Verified: `?lat=37.77` → 200 live, 24 aircraft;
`?lat=33.82` → 200 live, 15 aircraft; `#source` now reads `live traffic` on the
merged board and stays `""` on the coarse one.

**TWO INSTRUMENTS, BOTH BECAUSE THIS SESSION KEPT FAILING WITHOUT THEM.**

`scripts/performance-budget.mjs` gains a `california-one` cell. Until now the
only way to measure the merged board was to hand-edit the `california` cell's
query, run, and edit it back — done six times in one session, which is exactly
the procedure that gets half-done. Its `ready` asserts `#sea-section`, not just
the signature chapter: `california-overview` is on the coarse board too, so a
cell whose `?one=1` quietly stopped working would measure the coarse board and
pass. No ports, no section, no readiness. Caps are RECORDED from its first run
with headroom, in the same spirit as bay-area and socal — they were briefly
copied from `california` and that is wrong for the same reason that cell's
numbers are wrong for this board. **No existing cap was raised.**

`scripts/look.mjs` gains `--lat/--lng/--standoff/--height`. Every aim in this
harness goes through a control a reader also uses, which is right and stays the
default — but it means a board can only be photographed where a chapter already
points, and the merged board carries the state pack's six: the whole state, the
north, two corridors, two doors. None is near a city. The board exists to put
cities on the state and there was no way to photograph one; three attempts by
clicking the minimap and guessing wheel notches landed in open ocean twice and
on empty coast once. The seek moves the camera and nothing else.

**A regression the new cell caught within one run.** The first version of the
marker fix gated on bounds alone, like the office doors. The coarse state
board's rectangle contains San Francisco, so it picked up forty-four company
markers it has no business drawing at 1,919 m to the unit: 373 draw calls → 417.
Now gated on `carriesMetroDetail` as well, and `california` measures 372,415
triangles / 373 draws — identical to before this commit.

All twelve budget cells pass. 1,705 tests pass.

Recorded for the next round, from the review: **SoCal's two focus rectangles
overlap by 1.7 x 4.6 km** (verified: lat 34.075–34.090, lng −118.300–−118.250),
so any per-rectangle terrain tier must clip them to a disjoint cover first or it
draws that ground twice. Today's per-axis lattice is what hides it.

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

440 lines
19 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Render the built app and write a PNG you can open and judge.
*
* The defects this exists for cannot be asserted. "The ocean has no specular
* response", "the board ends in a hard diamond edge", "the aircraft are
* illegible at board scale" are all true of code that typechecks, passes every
* test and meets every performance budget. The only instrument that finds them
* is a picture, so this makes taking one cheap.
*
* node scripts/look.mjs <name> [--url <path-and-query>] [--phone] [--at <iso>]
* [--wait <ms>] [--click <text>] [--api <origin>]
* [--chapter <data-view>] [--expect <short label>]
*
* `--chapter` aims at a chapter by its **identity** — the `data-view` attribute
* the button carries, which is the chapter's id in the city pack — and not by
* its position in the list or by the text printed on it. Both of the other two
* have already produced a photograph of somewhere else in this repo: an index
* because a pack was reordered under it, and button text because two of
* California's six chapters are *doors* whose labels ("LA", "SF") match a
* click and then leave the board entirely. `--expect` asserts the printed short
* label as a second, independent check on the same button, which is what
* `scripts/brand-assets/shots.mjs` does and is worth keeping.
*
* Writes /tmp/tera-look/<name>.png. `--at` pins the clock, because the sun's
* position is computed from the real one and a shot taken at 03:00 tells you
* nothing about how the water reads at noon.
*
* This box has an AMD card and no monitor; the ANGLE/Vulkan flags below are what
* make Chrome render headless here rather than falling back to a blank canvas.
*/
import { spawn } from "node:child_process";
import { mkdirSync, readFileSync } from "node:fs";
import { createServer } from "node:net";
import { chromium } from "playwright";
const args = process.argv.slice(2);
const name = args[0] ?? "look";
/**
* The frames this project keeps taking, by name.
*
* `node scripts/look.mjs sf-night` and nothing else — no query string to
* remember and no timestamp to get wrong. The point is not convenience, it is
* that two people asking for "the night board" get the same photograph: an
* acceptance criterion that reads "shoot sf-night and look at it" is only worth
* writing if `sf-night` means one thing.
*
* Every field is a default. An explicit flag on the command line still wins, so
* a preset is a starting point rather than a cage, and adding one is two lines.
*/
const PRESETS = {
// The fire boards. California is the one with fires on it on a normal day;
// SoCal is the one that must be *empty* and say so — see ARCHITECTURE.md §9.2.
"fires-california": { url: "/?city=california" },
"fires-socal": { url: "/?city=socal" },
// The LA studio's upper floor. The door lands on the SF studio, so the shot
// switches rooms and waits for the swap.
"mateo-loft": { url: "/?city=socal&view=office", click: "LA HQ" },
// Night. 04:35Z is 21:35 in Los Angeles: full dark, and well clear of both
// twilight edges, so a shot taken a minute late is the same shot.
"sf-night": { url: "/?city=sf", at: "2026-08-23T04:35:00Z" },
"sky-night": { url: "/?city=california", at: "2026-08-23T04:35:00Z" },
"socal-night": { url: "/?city=socal", at: "2026-08-23T04:35:00Z" },
/*
* The aeroplane glyph, at the four stand-offs its clamp has to serve.
*
* TWO OF THESE WERE PHOTOGRAPHS OF SOMEWHERE ELSE, AND THE SET AS A WHOLE WAS
* DESCRIBED WRONG. The old comment read "a whole board, two chapter closeups
* on that board, and a detailed metro", and `glyph-la` / `glyph-sf` were
* `click: "^LA$"` / `click: "^SF$"` — the California board's chapters 04 and
* 05. Neither of those is a camera pose. Both are matched against
* `CALIFORNIA_DESTINATIONS` in `main.ts` and call `switchCity()` rather than
* `flyTo()`, so clicking them left California entirely: `glyph-la` returned a
* SoCal frame and `glyph-sf` a Bay Area one, byte-comparable to `hero-socal`
* and `hero-sf`. Two of the four stand-offs the set claimed to cover were
* duplicates of two others.
*
* Photographing the fix turned up the rest of it. California's six chapters
* are one whole-board pose, TWO DRIVES (`la-sf-us-101` and `la-sf-i-5` call
* `requestControlMode("drive")` at `main.ts:4493`, so clicking either lands a
* chase camera on a freeway, not a stand-off), two doors, and the north. The
* state board therefore has exactly TWO aerial poses on it — `State` and
* `North` — and "two chapter closeups on that board" was never available.
*
* So the clamp's four stand-offs are spread across the boards that have them,
* which is a better ladder anyway: three orders of magnitude of stand-off,
* every rung an aerial camera, every rung aimed by `data-view`.
*/
"glyph-board": { url: "/?city=california", chapter: "california-overview", expect: "State" },
"glyph-north": { url: "/?city=california", chapter: "shasta-cascades", expect: "North" },
"glyph-bay": { url: "/?city=sf", chapter: "bay-area", expect: "The Bay" },
"glyph-fidi": { url: "/?city=sf", chapter: "fidi", expect: "FiDi" },
/*
* The corridor, which is a drive and is photographed as one.
*
* These are what `glyph-la` and `glyph-sf` now resolve to: the two California
* chapters that stay on the California board. They are named for what they
* are rather than for the glyph, because the frame they produce is a chase
* camera behind the EV and no aeroplane is in it.
*/
"corridor-101": { url: "/?city=california", chapter: "la-sf-us-101", expect: "101" },
"corridor-i5": { url: "/?city=california", chapter: "la-sf-i-5", expect: "I-5" },
// The opening move, landed. `--reduced` collapses it to a cut, which is what
// makes an arrival frame reproducible.
"hero-california": { url: "/?city=california" },
"hero-socal": { url: "/?city=socal" },
"hero-sf": { url: "/?city=sf" },
};
/**
* Old names that still have to answer, pointed at what they always meant.
*
* Deleting them would be tidier and worse: `glyph-la` appears in the write-ups
* that commissioned these frames, and a name that 404s sends somebody back to
* `--click "^LA$"`, which is the exact command that produced the wrong picture.
* An alias that says out loud what it resolved to cannot do that.
*/
const ALIASES = {
"glyph-la": "corridor-101",
"glyph-sf": "corridor-i5",
};
const resolved = ALIASES[name] ?? name;
if (resolved !== name) {
console.log(
`look: "${name}" is an alias for "${resolved}". The California board's LA and SF chapters ` +
`are doors into the metro boards, not camera poses, so a preset named for them used to ` +
`photograph the other board. The two chapters that stay on California are the corridor ` +
`legs, and both open in DRIVE mode — for the aeroplane glyph's aerial stand-offs use ` +
`glyph-board, glyph-north, glyph-bay, glyph-fidi.`,
);
}
const preset = PRESETS[resolved] ?? {};
const flag = (f, d) => {
const i = args.indexOf(f);
if (i !== -1) return args[i + 1];
return preset[f.replace(/^--/, "")] ?? d;
};
const has = (f) => args.includes(f);
const OUT = "/tmp/tera-look";
mkdirSync(OUT, { recursive: true });
/**
* The port is asked for, not guessed, and the build is then verified.
*
* This used to draw a random port in 47004899 and start `vite preview
* --strictPort` on it. When the draw collided with an abandoned preview from an
* earlier run — and this box accumulated a hundred and forty-seven of them in
* one afternoon — the new preview exited on the strict-port check, `page.goto`
* succeeded against the squatter, and Playwright silently photographed somebody
* else's dist. Three shots came back byte-identical while the bundle under them
* provably changed. A screenshot tool that can photograph the wrong build is
* worse than no screenshot tool, because you believe it.
*
* So: take a port from the kernel rather than from `Math.random`, then read the
* URL the preview actually bound out of its own stdout, then fetch `/` and
* assert it is the `dist/index.html` sitting on this disk. Any one of the three
* would have caught it; all three cost nothing.
*/
const PORT = await new Promise((resolve, reject) => {
const probe = createServer();
probe.once("error", reject);
probe.listen(0, "127.0.0.1", () => {
const { port } = probe.address();
probe.close(() => resolve(port));
});
});
// `detached`, and vite's own binary rather than `npx`, because of the *other*
// half of the orphan story: `npx` is a wrapper, `server.kill()` killed only the
// wrapper, and the preview it had spawned went on holding its port forever. A
// hundred and forty-seven of them accumulated in one afternoon. Detached gives
// the pair a process group, and killing the group at the end kills both.
const server = spawn(
new URL("../node_modules/.bin/vite", import.meta.url).pathname,
["preview", "--port", String(PORT), "--strictPort"],
{ detached: true, stdio: ["ignore", "pipe", "pipe"] },
);
const shutdown = () => {
try {
process.kill(-server.pid, "SIGTERM");
} catch {
/* already gone */
}
};
process.on("exit", shutdown);
const bound = await new Promise((resolve) => {
let seen = "";
const settle = setTimeout(() => resolve(null), 30000);
const read = (chunk) => {
seen += String(chunk);
const match = /http:\/\/(?:localhost|127\.0\.0\.1):(\d+)/.exec(seen);
if (match) {
clearTimeout(settle);
resolve(Number(match[1]));
}
};
server.stdout.on("data", read);
server.stderr.on("data", read);
});
if (bound === null) {
console.error(`look: vite preview never announced a URL on ${PORT}; is dist/ built?`);
shutdown();
process.exit(1);
}
if (bound !== PORT) {
console.error(`look: preview bound ${bound}, not ${PORT} — refusing to photograph it`);
shutdown();
process.exit(1);
}
// And the served page is this checkout's build, hashed script tag and all.
{
const served = await fetch(`http://localhost:${PORT}/index.html`).then((r) => r.text());
const onDisk = readFileSync(new URL("../dist/index.html", import.meta.url), "utf8");
const bundle = (html) => /src="([^"]*\/assets\/[^"]+\.js)"/.exec(html)?.[1] ?? null;
if (bundle(served) === null || bundle(served) !== bundle(onDisk)) {
console.error(
`look: :${PORT} is serving ${bundle(served)}, dist/ holds ${bundle(onDisk)}` +
`something else owns that port. Not photographing it.`,
);
shutdown();
process.exit(1);
}
}
const phone = has("--phone");
const browser = await chromium.launch({
channel: "chrome",
args: [
"--use-gl=angle",
"--use-angle=vulkan",
"--enable-unsafe-swiftshader",
"--ignore-gpu-blocklist",
],
});
/**
* `--reduced` asks the page for `prefers-reduced-motion: reduce`.
*
* Which is not only an accessibility check. The opening arrival — `arrive()` in
* `scene.ts`, and `beginOfficeArrival` in `main.ts` — collapses to a cut under
* this preference, so a shot taken with it is the resting frame and nothing
* else, whatever the machine's load did to the four and a half seconds before
* it. Without it a slow build and a fast one photograph different cameras.
*/
const context = await browser.newContext({
viewport: phone ? { width: 390, height: 844 } : { width: 1600, height: 1000 },
deviceScaleFactor: 2,
timezoneId: "America/Los_Angeles",
...(has("--reduced") ? { reducedMotion: "reduce" } : {}),
...(phone
? {
isMobile: true,
hasTouch: true,
userAgent:
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 " +
"(KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",
}
: {}),
});
await context.clock.setFixedTime(new Date(flag("--at", "2026-08-21T20:00:00Z")));
const page = await context.newPage();
/**
* `--api http://127.0.0.1:8431` photographs the dist against a real server.
*
* `vite preview` serves the static build and nothing else, so without this every
* frame is the **keyless** experience: `/api/v1/health` 404s, `access` resolves
* with no `feeds` at all, and the weather, the aircraft, the satellites and the
* fires are all off. That is the right default — CONTRACT §0's stranger is
* exactly that visitor, and most frames should be shot as they see them — but it
* makes the one question a fire board exists to answer unphotographable.
*
* Proxied through Playwright rather than through a Vite config, for two reasons.
* The build is not modified, so what is photographed is byte-identical to what
* ships; and the response is *fulfilled* rather than redirected, so the page
* sees a same-origin answer and no CORS header has to exist on the API for a
* screenshot to work.
*/
const api = flag("--api", "");
if (api !== "") {
const base = api.replace(/\/+$/, "");
await page.route("**/api/v1/**", async (route) => {
const url = new URL(route.request().url());
try {
const response = await route.fetch({ url: `${base}${url.pathname}${url.search}` });
await route.fulfill({ response });
} catch (error) {
// A refused upstream must look like a refused upstream, not like a hung
// request: the app's own degraded paths are part of what is being judged.
console.log(`look: api proxy failed for ${url.pathname}${error}`);
await route.fulfill({ status: 502, body: "{}", contentType: "application/json" });
}
});
}
const errors = [];
page.on("console", (m) => {
if (m.type() === "error") errors.push(m.text());
});
await page.goto(`http://localhost:${PORT}${flag("--url", "/")}`, {
waitUntil: "networkidle",
timeout: 60000,
});
await page.waitForTimeout(Number(flag("--wait", "10000")));
// The first-run flow covers the scene it is teaching you about.
try {
await page.getByText(/^Skip$/).first().click({ timeout: 2500 });
await page.waitForTimeout(1200);
} catch {
/* already dismissed, or not shown */
}
/**
* The chapter, by identity, before any `--click`.
*
* `flyTo` eases over about two seconds of scene time, so the wait after it is
* the same 8 s a click gets. The label check is a hard failure rather than a
* log line: a preset that silently photographs the wrong chapter is worse than
* one that refuses, because the picture still looks deliberate.
*/
/*
* `--lat/--lng` plants the camera at a place instead of at a chapter.
*
* Every other aim in this harness goes through a control a reader also uses,
* and that stays the default: `--chapter` clicks a chapter button. But a board
* can then only be photographed where a chapter already points, and the merged
* "one California" board carries the state pack's six — the whole state, the
* north, two corridors and two doors — none of which is near a city. The board
* exists to put cities on the state, and there was no way to take a picture of
* one. Three attempts by clicking the minimap and guessing wheel notches landed
* in open ocean twice and on empty coast once.
*
* The seek moves the camera and nothing else. `--standoff` and `--height` are
* true metres, so a pose reads the same on a 94 m board and a 1,919 m one.
*/
const seekLat = flag("--lat", null);
const seekLng = flag("--lng", null);
if (seekLat !== null && seekLng !== null) {
const at = {
lat: Number(seekLat),
lng: Number(seekLng),
standoffM: Number(flag("--standoff", "20000")),
heightM: flag("--height", null) === null ? undefined : Number(flag("--height", "0")),
azimuth: flag("--azimuth", null) === null ? undefined : Number(flag("--azimuth", "0")),
};
const placed = await page.evaluate((pose) => {
const cam = globalThis.__teraCamera;
if (!cam || typeof cam.seek !== "function") return null;
return { board: cam.board, ...cam.seek(pose) };
}, at);
if (placed === null) {
console.error("look: no camera hook on the page — is this a build with publishCameraHook?");
process.exit(1);
}
console.log(
`look: seek ${at.lat},${at.lng} on ${placed.board} — standoff ${at.standoffM} m`,
);
await page.waitForTimeout(Number(flag("--settle", "2500")));
}
const chapter = flag("--chapter", null);
if (chapter !== null && chapter !== "") {
const expect = flag("--expect", null);
const found = await page.evaluate((id) => {
const button = document.querySelector(`#chapters .chapter[data-view="${id}"]`);
if (!(button instanceof HTMLElement)) {
return {
ok: false,
available: [...document.querySelectorAll("#chapters .chapter")].map((node) =>
node.getAttribute("data-view"),
),
};
}
const spans = [...button.querySelectorAll("span")];
const label = (spans[spans.length - 1]?.textContent ?? "").trim();
const index = button.getAttribute("data-view-index");
button.click();
return { ok: true, label, index };
}, chapter);
if (!found.ok) {
console.error(
`look: no chapter with data-view="${chapter}" on this board — it has ` +
`${JSON.stringify(found.available)}. Not photographing a frame nobody asked for.`,
);
await browser.close();
shutdown();
process.exit(1);
}
if (expect !== null && found.label !== expect) {
console.error(
`look: chapter "${chapter}" prints "${found.label}", the preset expects "${expect}" — ` +
`a pack was re-labelled, so this shot would be captioned wrong.`,
);
await browser.close();
shutdown();
process.exit(1);
}
console.log(`look: chapter ${chapter} — "${found.label}" at position ${found.index}`);
await page.waitForTimeout(8000);
}
/**
* `--click` may be given more than once, and they run in order.
*
* One click opens a door; two get you somewhere inside it. The LA office's
* upper storey is the case that forced this: the first click opens the
* building and the second flies to a viewpoint on the floor above, and there is
* no single label that does both.
*/
const clicks = args.flatMap((arg, i) => (arg === "--click" ? [args[i + 1] ?? ""] : []));
if (clicks.length === 0 && typeof preset.click === "string") clicks.push(preset.click);
for (const click of clicks) {
if (click === "") continue;
try {
await page.getByText(new RegExp(click, "i")).first().click({ timeout: 5000 });
await page.waitForTimeout(8000);
} catch {
console.log(`look: could not click ${click}`);
}
}
const path = `${OUT}/${name}.png`;
await page.screenshot({ path });
console.log(`look: wrote ${path}`);
// Two 404s on a static preview are the zero-config path working: see deploy/STATIC.md.
const real = errors.filter((e) => !/404|Failed to load resource/.test(e));
console.log(real.length === 0 ? "look: no console errors" : `look: ERRORS ${JSON.stringify(real)}`);
await browser.close();
shutdown();
// Explicit, because the preview's stdout pipes are inherited by a grandchild
// and Node will happily wait on them for the rest of the afternoon.
process.exit(0);