1
0

feat: the state becomes California, and the port fills with ships

**Stage 1 of one California.** The owner's complaint had two halves and this is
the first: the state board was a CROPPED SLAB. `california.ts` stopped at 38.05 N,
so the board disagreed with its own minimap about the shape of California in a
single frame, and Bug Fire's 93,733 acres burned off-frame while the panel said
all clear. Bounds now run 32.50-42.05 N / -124.50 to -114.0 W — Cape Mendocino,
the ruled Oregon parallel, the 120th-meridian corner into the Nevada diagonal.

**And it got cheaper.** 391,169 triangles to 375,351, while gaining the North
Coast, the Sacramento Valley, the Klamath knot, the Cascade arc, Shasta at 4,320 m
and Lassen at 3,190 m. Extending the bounds alone would have doubled the lattice
to 168,813 points and blown the mobile cap; coarsening cellLat 0.022 -> 0.0312 and
cellLng 0.027 -> 0.0383 holds it at ~83,800. The cell as a FRACTION of the board
moves 0.0030 -> 0.0033 — unchanged in frame — because the camera retreats to frame
whatever it is given. That argument was already written in the pack's own comment.

The second half — three boards becoming one world you zoom through — is NOT here.
Merging at Bay density would be 34.04M triangles, 13x the highest budget, and
merging at SoCal density would downgrade San Francisco from 40 m lots to 164 m.
Both delete the board every marketing still is shot from. `sf.ts` and `socal.ts`
are untouched by design.

**Aerial perspective, which the state board could not have had before.** The old
fog started at 1.15 board spans = 944 km, on a board whose longest diagonal is
820 km — so no pixel could ever be fogged. Fog now responds to camera altitude,
clamped to the authored pair as a ceiling.

`Atmosphere.aerial(env, view)` is a second pure method returning `{ near, far }`
and **deliberately no colour**. That is structural, not stylistic: it is why a
future camera-dependent term cannot reach `environmentKey()`'s colour fingerprint
and start rebuilding the PMREM cubemap on every camera step. Coarsening the
fingerprint instead would have hidden one instance and armed the mechanism. A
mutation-tested seam guard fails if anyone merges the two paths back together.

**The port.** Terminal Island rendered as a bare tan polygon with generic white
blocks while the chapter text called it the busiest port complex in the
hemisphere. Now six container yards drawn as canvas atlases, 56 gantry cranes at
varied boom angles, the 13 km San Pedro breakwater, the dredged channel. Five
buckets merging ACROSS ports the way airports.ts merges across fields, so a
second complex costs no extra draws: +11 draws and +4,377 triangles for all of it.

At vertical exaggeration 3.4 a 130 m gantry is 1.132 units tall against a 400 m
ship's 1.024 long — the crane is the taller object, and it is what makes a port
read as a port from altitude.

**Ships, and the wake carries the information.** Moored hulls have no foam,
verified at three terminals; a tug under way in the Main Channel trails a clean
Kelvin V. One hull geometry, one InstancedMesh, orientation from the BERTH rather
than the wire. The AIS gate strips sog 102.3, heading 511 and cog 360 — all mean
"not available" — with an explicit test that cog 358.7 SURVIVES, because a naive
range check on cog eats real headings near north.

"Empty or full" is not in AIS position reports and is not invented per ship. The
honest answer is at port level and is a better story: 348,691 of 460,467 boxes
left Los Angeles empty in July 2026, corroborated by FBX01 $7,491 inbound against
FBX02 $347 outbound.

**Radar and birds ship dark, and say why.** California is 0.47% wet and migration
is nocturnal and seasonal, so both layers have nothing to say on most days. The
panel reads "No radar feed is configured, so this board draws no weather. That is
a fact about this box, not about the sky."

Also recorded, and it matters beyond this commit: **the GPU on amd-server never
leaves 500 MHz of a possible 2725**, traced across 80 seconds of sustained load.
`bay-area/desktop` is fragment-bound at that clock and sits on the vsync deadline,
so a trivial change in fragment work flips it between 16.8 and 33.3 with geometry
identical to the digit. Every frame-time number measured on this box is a floor.
Two investigations reached two different wrong conclusions from single-run
comparisons before this was traced. Geometry is the gate; frame time is advisory.
No cap was raised.

Tests 1,340 -> 1,540, server 280 -> 295.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-22 23:35:09 -07:00
parent b25f217e3e
commit acf4d1a510
52 changed files with 14436 additions and 142 deletions
+188
View File
@@ -0,0 +1,188 @@
/**
* The migration feed's one upstream: a **projection**, served by the machine
* that owns the database.
*
* The same arrangement as `fires/cloud1.ts` and `radar/cloud1.ts`, and it is
* worth saying why it applies here too even though `birds.sqlite` holds nothing
* private. The value is not only in what this particular store contains: it is
* that **cloud-2 has no database at all**, so no route written on this box next
* year can select a column from any of them. Making that true of every feed is
* what keeps it true of the one that matters.
*
* ### Both halves, or neither
*
* The newest ten-minute granule and last night's state summary are asked for in
* parallel, and `null` comes back if either fails. That matters more here than
* anywhere else in this build, because the two halves answer *different*
* questions and the second one is the whole empty state: without last night's
* figures the daylight sky has nothing to say but "nothing is aloft", which is
* the blank panel this layer was designed to avoid.
*
* ### The state row is dropped on the way in, and again on the way out
*
* `counties` upstream is 59 rows: 58 counties plus `US-CA`, `kind='state'`, with
* NULL coordinates and — in tonight's granule — 793,141 birds aloft against the
* largest county's 82,549. It is refused here by `countyRows`, refused again by
* `promoteBirds` in the browser, and a third time by the layer's own reader.
* Three lines for one row is not paranoia: the failure it prevents is a
* three-quarter-million-bird blob at 0,0, and the reason it would happen is that
* the row looks exactly like the other fifty-eight.
*/
import { getJson } from "../http.ts";
import { countyRows } from "../../../src/server/birds.ts";
import type { WireBirdCounty } from "../../../src/server/wire.ts";
/** How long either GET may take. */
const TIMEOUT_MS = 8_000;
/** California has 58 counties; the cap is a bound on a bad day, not a fit. */
const MAX_COUNTIES = 256;
export interface BirdsSnapshot {
/** Epoch ms at which this box completed the fetch. */
fetchedAt: number;
/** ISO-8601 of the ten-minute granule, or "" if the upstream sent none. */
observedAt: string;
counties: WireBirdCounty[];
/** Last night, from the state row. Never a sum over counties. */
statewide: {
crossed: number;
peakAloft: number;
peakAt: string;
meanAltitude: number;
heading: string;
} | null;
attribution: string[];
}
export interface BirdsLog {
warn(msg: string): void;
}
interface CountiesResponse {
observedAt?: unknown;
counties?: unknown;
attribution?: unknown;
}
interface NightResponse {
night?: unknown;
attribution?: unknown;
}
export async function fetchProjection(
base: string,
key: string,
log: BirdsLog,
): Promise<BirdsSnapshot | null> {
if (base === "") return null;
const headers = key === "" ? undefined : { "x-tera-key": key };
const options = { timeoutMs: TIMEOUT_MS, ...(headers === undefined ? {} : { headers }) };
const [countiesBody, nightBody] = await Promise.all([
getJson<CountiesResponse>(`${base}/counties`, options),
getJson<NightResponse>(`${base}/night`, options),
]);
if (countiesBody === null || nightBody === null) {
log.warn(
"birds:cloud1: the projection did not answer with both halves " +
`(counties ${countiesBody === null ? "failed" : "ok"}, ` +
`night ${nightBody === null ? "failed" : "ok"}); keeping the last whole body`,
);
return null;
}
const rows = readArray(countiesBody.counties, MAX_COUNTIES, readCounty);
return {
fetchedAt: Date.now(),
observedAt: nonEmptyString(countiesBody.observedAt) ?? "",
// The state row goes here and not downstream. Everything past this point is
// a county with a coordinate and an area.
counties: countyRows(rows),
statewide: readNight(nightBody.night),
attribution: mergeAttribution(countiesBody.attribution, nightBody.attribution),
};
}
// ---- Reading somebody else's JSON -----------------------------------------
function readCounty(raw: unknown): WireBirdCounty | null {
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return null;
const row = raw as Record<string, unknown>;
const id = nonEmptyString(row.id);
const lat = finite(row.lat);
const lon = finite(row.lon);
const areaKm2 = finite(row.areaKm2);
// No id, no coordinate or no area means nothing downstream can place it or
// scatter it. All three are structural, not cosmetic — and the state row is
// missing two of the three, which is the second reason it never survives.
if (id === null || lat === null || lon === null || areaKm2 === null) return null;
return {
id,
name: nonEmptyString(row.name) ?? "",
lat,
lon,
areaKm2,
aloft: Math.max(0, finite(row.aloft) ?? 0),
altitude: Math.max(0, finite(row.altitude) ?? 0),
direction: finite(row.direction) ?? 0,
speed: Math.max(0, finite(row.speed) ?? 0),
};
}
/**
* Last night's state row.
*
* `null` rather than a zeroed object when it is missing, because zero birds
* crossing California is a finding and an absent summary is not one.
*/
function readNight(raw: unknown): BirdsSnapshot["statewide"] {
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return null;
const row = raw as Record<string, unknown>;
const crossed = finite(row.crossed);
const peakAloft = finite(row.peakAloft);
if (crossed === null || peakAloft === null) return null;
return {
crossed,
peakAloft,
peakAt: nonEmptyString(row.peakAt) ?? "",
meanAltitude: Math.max(0, finite(row.meanAltitude) ?? 0),
heading: nonEmptyString(row.heading) ?? "",
};
}
function readArray<T>(raw: unknown, cap: number, read: (row: unknown) => T | null): T[] {
if (!Array.isArray(raw)) return [];
const out: T[] = [];
for (const row of raw) {
if (out.length >= cap) break;
const parsed = read(row);
if (parsed !== null) out.push(parsed);
}
return out;
}
function mergeAttribution(a: unknown, b: unknown): string[] {
const out: string[] = [];
for (const source of [a, b]) {
if (!Array.isArray(source)) continue;
for (const line of source) {
if (typeof line !== "string" || line === "" || out.includes(line)) continue;
out.push(line);
}
}
return out;
}
function nonEmptyString(value: unknown): string | null {
if (typeof value !== "string") return null;
const trimmed = value.trim();
return trimmed === "" ? null : trimmed;
}
function finite(value: unknown): number | null {
return typeof value === "number" && Number.isFinite(value) ? value : null;
}
+122
View File
@@ -0,0 +1,122 @@
/**
* Which migration this box serves — California's, or none.
*
* The same shape as `fires/index.ts` and `radar/index.ts`. One body, one cache
* key, no region parameter: the whole state's granule is 58 rows and every board
* is a rectangle inside it, so a server that filtered by board would be doing a
* worse version of a clip the client has to do anyway (`promoteBirds` in
* `src/server/birds.ts`).
*
* ### The empty body carries a reason, and that is the difference from fires
*
* A fire body with nothing in it needs no explanation beyond its own age:
* nothing is burning. An empty *migration* body needs one, because the layer is
* absent about fourteen hours in every twenty-four by construction and a viewer
* arriving at noon would otherwise read a working feed as a broken one. So
* `quiet` is not optional on the wire and is filled in here even for a box with
* no source at all.
*
* ### `none` is a quiet sky, not an invented flock
*
* The same asymmetry `fires/index.ts` argues. An invented aeroplane is a
* plausible aeroplane; three hundred thousand invented birds over a named county
* is a claim about a real place. So the synthetic case is the honest quiet one —
* which is also what keeps `scripts/check-zero-config-boot.mjs` green with
* `TERA_BIRDS_SOURCE` unset.
*/
import { fetchProjection, type BirdsSnapshot } from "./cloud1.ts";
import { createUpstream } from "../upstream.ts";
import type { Config } from "../config.ts";
import type { BirdsBody } from "../../../src/server/wire.ts";
export interface BirdsService {
current(): Promise<BirdsBody>;
}
export interface BirdsLog {
warn(msg: string): void;
}
const CALIFORNIA_KEY = "california";
/**
* Five minutes.
*
* Granules are ten minutes apart and the collector reads them in batches about
* twenty minutes behind, so anything faster is two machines' work for identical
* bytes. Floored for the reason every other feed here is floored:
* `TERA_BIRDS_TTL=0` reads like "fresh" and means "one fetch pair per request".
*/
const MIN_TTL_SECONDS = 300;
/**
* What a box with no source answers with.
*
* Note the `quiet` reason: `no-data`, not `daylight`. Nobody has looked, which
* is a different thing from having looked and found the sun up, and the panel
* says so in words rather than showing the same blank for both.
*/
function emptyBody(ttlSeconds: number): BirdsBody {
return {
source: "none",
fetchedAt: new Date(0).toISOString(),
observedAt: null,
counties: [],
statewide: null,
quiet: {
reason: "no-data",
message:
"No migration feed is configured on this box, so nothing is drawn over " +
"the state. That is a fact about this box, not about the sky.",
},
ttlSeconds,
};
}
export function createBirdsService(config: Config, log: BirdsLog): BirdsService {
const { source, url, key, ttlSeconds } = config.birds;
const ttl = Math.max(MIN_TTL_SECONDS, ttlSeconds);
const upstream = createUpstream<BirdsSnapshot>({
label: "birds:cloud1",
ttlSeconds: ttl,
log,
});
return {
async current(): Promise<BirdsBody> {
if (source === "none") return emptyBody(ttl);
const snapshot = await upstream.get(CALIFORNIA_KEY, () => fetchProjection(url, key, log));
if (snapshot === null) return emptyBody(ttl);
// Whether the sky is quiet is decided in the browser, where the sun's
// elevation is already known to a hundredth of a degree
// (`atmosphere.ts`). The server would have to compute a second opinion
// from a clock the scrubber does not own, and the two would disagree on
// exactly the frames that matter. So `quiet` is `null` here whenever
// anything at all arrived, and `promoteBirds` fills it in.
const quiet: BirdsBody["quiet"] =
snapshot.counties.length > 0
? null
: {
reason: "no-data",
message:
"The migration feed answered with no counties in it. " +
"Either the newest granule has not landed yet or nothing was measured.",
};
return {
source,
fetchedAt: new Date(snapshot.fetchedAt).toISOString(),
observedAt: snapshot.observedAt === "" ? null : snapshot.observedAt,
counties: snapshot.counties,
statewide: snapshot.statewide,
quiet,
ttlSeconds: ttl,
...(snapshot.attribution.length > 0 ? { attribution: snapshot.attribution } : {}),
};
},
};
}