1
0

feat: real fire on the boards, the LA office as a twin, and a night sky worth reading

The world stops being a simulation of California and starts being California.

**THE PROMOTION GATE WAS THE FIRST COMMIT, BEFORE ANY ORANGE PIXEL EXISTED.**
On today's live store the SoCal board contains 22 incidents. Every one has NULL
acreage and fifteen are nameless LA County dispatch numbers. Drawn naively that
is 22 orange marks over Los Angeles on a day nothing is burning — in a frame that
contains no other warm colour, so one glyph would be the most salient object on
the board and twenty-two would spend its credibility permanently.

`acres >= 10 AND contained < 80 AND type != 'RX' AND last_seen = max(last_seen)`
returns 0 on SoCal, exactly 5 on California, 0 on the Bay — same body, same day,
three correct answers. The empty board is a deliverable, not a fallback: it says
"No active fire on this board — CAL FIRE and WFIGS, just now", states that 21
records were gated and why, lists the largest fires burning OUTSIDE the frame
with distances, and counts the hot pixels it is deliberately not drawing.

**The privacy leak is structurally impossible rather than carefully avoided.**
cloud-1 serves a projection; the four home-relative columns never leave that box.
`observations.threat` was the one that nearly got through — it is
`(16/distance)^2 x log10(acres) x momentum x containment x wind-alignment`, so
with acreage and containment public it inverts to a distance circle around a
house and three fires give an intersection. A grep of the built bundle for
distance_km, bearing_deg, threat, 7762 and the street name returns nothing.

**Deliberately not used, and both would have produced a confident wrong answer:**
the store's `air` table retains only the last parameter of each poll, so all 78
rows read "Good" while the live feed reports ozone 101 "Unhealthy for Sensitive
Groups" — haze driven off it would clear the sky during a smoke event. And
`weather` is written only inside the NWS alerts loop, so a quiet day stores no
wind at all. Tera's own per-region NWS wind is already correct and already what
the clouds drift on.

Satellite detections are drawn as evidence and never as incidents. The permanent
industrial heat source 4.7 km from the owner's house is flagged persistent and
dropped, asserted by a test that first proves it is present in the fixture.
MODIS integer confidence and VIIRS string confidence are branched on `sat`.

**The LA office is a twin.** Its entire authored second storey — Model Loft,
Model Bay, The Materials Room, 430 lines nobody had ever stood in — is reachable
on foot: a walker crosses level-1 to level-2 in 73 fixed steps, floorY 0 to 5,
verified against the real pack rather than a synthetic plan. Its two studio
devices read real hardware through a field-allowlisted bridge: mute, volume and
reachability only. Never level, because there is no passive level upstream and
obtaining one would record a room with people in it. Never dB, because upstream
is gainPct across four different native scales. The bridge refuses all writes.

Fixed at its root: an anonymous visitor was getting permanently at-rest
instruments backing off against a 401. The tier moves into `createDeviceSource`,
so anon gets the living simulator three file headers already promised.

**Item 8 is closed, not fixed, and the correction is the point.** The Bay Area
"stutter" was GPU power management — the card sat at 500 MHz of 2725 through
every run that reproduced it, 4096/2048/1024/256 shadow maps all render in
1.21-1.31 ms, and two consecutive runs over a byte-identical dist gave 33.4 then
16.7. The allowance is removed and the cell is back to 16.7. Geometry is the
gate; frame time is advisory.

Item 7 was re-scoped after measuring: 1,069,006 of the Bay Area's 2,265,056
triangles were the second submission of the same buildings into the shadow pass.
Mobile now has its own triangle caps and bay-area mobile draws 1,266,096.

Also: bridges and the freeway corridor light up at night as emission, not lights
— 1,614 deck lamps and 18 tower heads on the Bay in two draw calls. The single
change that made US-101 legible was moving its edge lines from the lit material
to the unlit one: retroreflective paint, the argument the SFO night frame already
makes. California went 21,991 lamps to 4,051, clustered at the 17 town districts,
because a rural interurban corridor genuinely is unlit.

Tests 1137 -> 1340, server 280. All ten budget cells pass on first attempt with
no cap raised.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-22 18:01:11 -07:00
parent b7f5c41da5
commit b25f217e3e
91 changed files with 15111 additions and 401 deletions
+99 -4
View File
@@ -8,7 +8,7 @@
* 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>]
* [--wait <ms>] [--click <text>] [--api <origin>]
*
* 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
@@ -25,9 +25,50 @@ 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: a whole
// board, two chapter closeups on that board, and a detailed metro.
"glyph-board": { url: "/?city=california" },
"glyph-la": { url: "/?city=california", click: "^LA$" },
"glyph-sf": { url: "/?city=california", click: "^SF$" },
"glyph-bay": { url: "/?city=sf", click: "The Bay" },
// 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" },
};
const preset = PRESETS[name] ?? {};
const flag = (f, d) => {
const i = args.indexOf(f);
return i === -1 ? d : args[i + 1];
if (i !== -1) return args[i + 1];
return preset[f.replace(/^--/, "")] ?? d;
};
const has = (f) => args.includes(f);
@@ -128,10 +169,20 @@ const browser = await chromium.launch({
],
});
/**
* `--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,
@@ -145,6 +196,40 @@ const context = await browser.newContext({
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());
@@ -164,8 +249,18 @@ try {
/* already dismissed, or not shown */
}
const click = flag("--click", "");
if (click !== "") {
/**
* `--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);