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
+204
View File
@@ -54,6 +54,7 @@ import type {
DeviceCommandResultBody,
DevicesBody,
DevicesSourceId,
FiresBody,
FlightsBody,
FlightsPlanBody,
HealthBody,
@@ -254,6 +255,30 @@ export interface DeviceWatch {
stop(): void;
}
/**
* A running poll of the state's active fires.
*
* `DeviceWatch`'s shape rather than `WeatherWatch`'s, because the caller needs
* the accessor: a board is drawn before this has answered, and a layer that had
* to wait a whole TTL for its first publish would show an empty board for ten
* minutes and be indistinguishable from a board with nothing on it. `current()`
* is `null` until something lands, which is a third state and is exactly the one
* a caption has to be able to say out loud.
*
* There is no fallback body underneath it and there never will be. An invented
* aeroplane is a plausible aeroplane; an invented wildfire is a claim that a
* named place is burning, made to somebody who may live there. `null` renders as
* a board that says it has not heard.
*/
export interface FireWatch {
/** The latest body, or `null` until one has arrived. */
current(): FiresBody | null;
/** Ask now rather than at the next tick. Ignored while a request is in flight. */
refresh(): void;
/** Stop polling, abort anything in flight, and drop any late answer. */
stop(): void;
}
export interface TeraClient {
/** What the deployment turned out to be, or `null` if there is no server. */
health(): Promise<HealthBody | null>;
@@ -289,6 +314,28 @@ export interface TeraClient {
* Not per-region and not watched — see the implementation for both reasons.
*/
satellites(options?: { signal?: AbortSignal }): Promise<SatelliteElements[]>;
/**
* Every active fire this deployment knows about, once. `null` when nothing
* answered — which a board must render as "I have not heard", never as "there
* is no fire".
*
* Not per-region, exactly like `satellites`: the whole state's live incident
* set is small, the boards are rectangles inside it, and the clip is
* `promote()` in `src/server/fires.ts`, which the client has to run anyway to
* apply the tier ladder. Asking the server to filter would be asking it to do
* a worse version of work that cannot be skipped, and would cost the one
* property that makes this cheap: one body, every viewer, one cache key.
*/
fires(options?: { signal?: AbortSignal }): Promise<FiresBody | null>;
/**
* The same question, asked on the feed's own cadence, until the caller stops.
*
* Ten minutes by default, because that is the upstream collector's cron and
* anything faster receives identical bytes. `onBody` fires on every settled
* poll including the ones that change nothing, so a board can restamp its "as
* of" line without waiting for a fire to move.
*/
watchFires(onBody: (body: FiresBody | null) => void): FireWatch;
/**
* One office pack. `null` for anything the server will not serve — including
* a private one, which answers 404 rather than 403 so the endpoint cannot be
@@ -517,6 +564,22 @@ export function createTeraClient(options: TeraApiOptions = {}): TeraClient {
return body.satellites;
},
/**
* The fires, once.
*
* `null` for every refusal, and the caller must not turn that into an empty
* board silently — `promote()` returns a promotion carrying `fetchedAt` and
* `ageMs` precisely so the difference can be printed. A board that draws
* nothing because nobody answered and a board that draws nothing because
* California is not burning are the same picture and different facts.
*/
fires: (opts: { signal?: AbortSignal } = {}) =>
get<FiresBody>("/fires", { ...(opts.signal ? { signal: opts.signal } : {}) }),
watchFires(onBody) {
return watchFires(get, onBody);
},
office: (id) => get<OfficeDoc>(`/offices/${encodeURIComponent(id)}`),
/**
@@ -1754,3 +1817,144 @@ function intervalFor(body: DevicesBody): number {
function devicesPath(officeId: string): string {
return `/offices/${encodeURIComponent(officeId)}/devices`;
}
// ---- Fires ----------------------------------------------------------------
/**
* How often to ask, when the server does not say.
*
* Ten minutes, which is the collector's own cron upstream and the server's
* `TERA_FIRES_TTL` default. Asking faster spends two machines' work to be handed
* the same bytes: the projection endpoint holds a sixty-second cache, the API
* holds ten minutes, and the data itself moves when an agency updates an
* incident — which for a large fire is a handful of times a day.
*
* The other end of the argument is what the board does with it. A fire glyph is
* a position and an acreage; neither moves in a way anyone can see over ten
* minutes, and the plume drifts on wind that arrives from a different feed
* entirely. This is a map, not a dispatch console.
*/
const FIRES_INTERVAL_MS = 10 * 60_000;
/** Bounds on whatever the server asks for, so one bad TTL cannot become a flood. */
const FIRES_MIN_INTERVAL_MS = 60_000;
const FIRES_MAX_INTERVAL_MS = 60 * 60_000;
/**
* The ceiling on the back-off ladder.
*
* An hour, `watchWeather`'s number rather than `watchDevices`'s five minutes,
* and for the reason `watchWeather` gives: the commonest deployment of this
* bundle is a static host with no API at all, where every poll fails forever.
* Nobody is standing inside a wildfire the way somebody is standing in the room
* a device watch describes.
*/
const FIRES_MAX_BACKOFF_MS = 60 * 60_000;
/**
* Poll the fire feed until told to stop.
*
* `watchDevices` without the change comparison. The publish-on-change trick is
* deliberately absent: an unchanged body still carries a **newer `fetchedAt`**,
* and that is the field a quiet board is captioned with. Suppressing a republish
* because no fire moved would freeze the age on screen at the moment of the last
* change, so a feed that died an hour ago would go on displaying "4 minutes
* ago" — which is the precise failure a stated fetch age exists to prevent.
*
* It keeps the other two properties: it stops dead while the tab is hidden and
* asks immediately on the way back, and it reports a refusal as `null` rather
* than freezing on the last good body.
*/
function watchFires(get: Get, onBody: (body: FiresBody | null) => void): FireWatch {
let body: FiresBody | null = null;
let failures = 0;
let stopped = false;
let timer: ReturnType<typeof setTimeout> | null = null;
let inFlight: AbortController | null = null;
function schedule(delayMs: number) {
if (stopped) return;
if (timer !== null) clearTimeout(timer);
timer = setTimeout(() => void tick(), delayMs);
}
async function tick(): Promise<void> {
timer = null;
if (stopped) return;
if (typeof document !== "undefined" && document.visibilityState === "hidden") return;
if (inFlight) {
schedule(FIRES_INTERVAL_MS);
return;
}
inFlight = new AbortController();
const next = await get<FiresBody>("/fires", { signal: inFlight.signal });
inFlight = null;
// Stopped while this was in the air — the board was left. Whatever came back
// describes a map nobody is looking at, and a cancelled request must not
// count as a failure.
if (stopped) return;
// Checked rather than trusted, like every other body this file adopts: a 200
// with the wrong shape in it is what a server one version behind this one
// sends, and `promote()` downstream would read it as an empty board.
const usable = next !== null && Array.isArray(next.incidents) ? next : null;
body = usable;
onBody(usable);
if (usable === null) {
failures += 1;
schedule(Math.min(FIRES_INTERVAL_MS * 2 ** (failures - 1), FIRES_MAX_BACKOFF_MS));
return;
}
failures = 0;
schedule(firesIntervalFor(usable));
}
function onVisibility() {
if (stopped) return;
if (document.visibilityState === "visible") {
failures = 0;
schedule(0);
} else if (timer !== null) {
clearTimeout(timer);
timer = null;
}
}
if (typeof document !== "undefined") {
document.addEventListener("visibilitychange", onVisibility);
}
void tick();
return {
current: () => body,
refresh() {
if (stopped || inFlight) return;
schedule(0);
},
stop() {
stopped = true;
if (timer !== null) clearTimeout(timer);
timer = null;
inFlight?.abort();
inFlight = null;
if (typeof document !== "undefined") {
document.removeEventListener("visibilitychange", onVisibility);
}
},
};
}
/**
* The cadence the server asked for, clamped.
*
* The floor is the load-bearing half, exactly as it is for devices: a
* `TERA_FIRES_TTL` of zero reaching a browser unchecked is one request per tick
* per open tab, against a box that is itself calling another machine.
*/
function firesIntervalFor(body: FiresBody): number {
const asked = Number.isFinite(body.ttlSeconds) ? body.ttlSeconds * 1000 : FIRES_INTERVAL_MS;
return Math.min(FIRES_MAX_INTERVAL_MS, Math.max(FIRES_MIN_INTERVAL_MS, asked));
}