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>
This commit is contained in:
@@ -1053,6 +1053,70 @@ export interface TrafficSource extends FlightSource {
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* One `TrafficSource` over several regions.
|
||||
*
|
||||
* A board that spans more than one served region cannot be a single circle.
|
||||
* `regionOf` derives its circle from the board's *bounds*, which on the merged
|
||||
* statewide board is 402 nautical miles centred on the middle of the state —
|
||||
* and the API refuses it, correctly: `400 bad_request, "Nothing this deployment
|
||||
* serves is near 37.3,-119.25"`. What this deployment serves is San Francisco
|
||||
* and the Southland, five hundred and sixty kilometres apart, and the honest
|
||||
* request is both of them rather than one circle drawn around the gap between.
|
||||
*
|
||||
* Here and not in `engine/flights.ts` for the reason `TrafficSource` itself is
|
||||
* here: the engine draws darts at coordinates and has no business with
|
||||
* provenance, and every interesting part of this merge — which regions are
|
||||
* live, whose attribution to carry — is provenance.
|
||||
*
|
||||
* Three properties worth stating, because each is a way this could be wrong:
|
||||
*
|
||||
* - **De-duplicated by id.** Regions may overlap, and two circles drawn around
|
||||
* neighbouring metros both see an aircraft between them. Drawn twice it gets
|
||||
* two glyphs and two trails, and `flights.ts` measures a track's span from
|
||||
* repeated observations, so a duplicate is not merely a double image.
|
||||
* - **`live()` is `some`, not `every`.** One dark metro must not make the
|
||||
* other's observed traffic claim to be simulated; the label is about what is
|
||||
* on screen. `describeFeeds` in `ui/chromeState.ts` reads this.
|
||||
* - **`poll()` stays synchronous**, as this interface narrows it to be. Each
|
||||
* source answers from what it has in hand, so merging is a concat and never
|
||||
* a round trip — a promise here would put a frame's aircraft behind the
|
||||
* network, which is the whole thing this file's design avoids.
|
||||
*/
|
||||
export function mergedTraffic(sources: readonly TrafficSource[]): TrafficSource {
|
||||
return {
|
||||
interval: sources.reduce((a, s) => Math.min(a, s.interval), Number.POSITIVE_INFINITY),
|
||||
poll(): Aircraft[] {
|
||||
const seen = new Set<string>();
|
||||
const out: Aircraft[] = [];
|
||||
for (const source of sources) {
|
||||
for (const aircraft of source.poll()) {
|
||||
if (seen.has(aircraft.id)) continue;
|
||||
seen.add(aircraft.id);
|
||||
out.push(aircraft);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
},
|
||||
live(): boolean {
|
||||
return sources.some((s) => s.live());
|
||||
},
|
||||
attribution(): string[] {
|
||||
return [...new Set(sources.flatMap((s) => s.attribution()))];
|
||||
},
|
||||
detail(id: string): AircraftDetail | null {
|
||||
for (const source of sources) {
|
||||
const found = source.detail(id);
|
||||
if (found !== null) return found;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
dispose(): void {
|
||||
for (const source of sources) source.dispose();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Traffic over HTTP, in whichever of the two shapes the server chose.
|
||||
*
|
||||
|
||||
@@ -130,6 +130,18 @@ let cached: { city: City; report: UnifyReport } | null = null;
|
||||
* The one board. Memoised, because `World` builds one per mount and the merge
|
||||
* walks every district polygon in the product.
|
||||
*/
|
||||
/**
|
||||
* The detailed packs this board was built from.
|
||||
*
|
||||
* Exported because a board that spans more than one served region has to ask
|
||||
* the live feeds for each of them — `regionOf` on the merged board's own bounds
|
||||
* is a 402-nautical-mile circle centred on the middle of the state, and the API
|
||||
* refuses it. `main.ts` derives one sky region per entry here instead. Reading
|
||||
* it from the merge rather than hard-coding two imports is what keeps a third
|
||||
* metro from being a change in two files.
|
||||
*/
|
||||
export const UNIFIED_SOURCES: readonly City[] = [SAN_FRANCISCO, SOCAL];
|
||||
|
||||
export function unifiedCalifornia(): { city: City; report: UnifyReport } {
|
||||
if (cached !== null) return cached;
|
||||
|
||||
|
||||
+130
-5
@@ -73,7 +73,7 @@ import { createStage, deviceProfile } from "./engine/stage.ts";
|
||||
import { daylightPhase } from "./engine/solar.ts";
|
||||
import type { Aircraft, City, Marker, MarkerPalette, Port, View } from "./engine/types.ts";
|
||||
import CALIFORNIA from "./cities/california.ts";
|
||||
import { unifiedCalifornia } from "./cities/unify.ts";
|
||||
import { UNIFIED_SOURCES, unifiedCalifornia } from "./cities/unify.ts";
|
||||
import { reconciledCity } from "./cities/reconcile.ts";
|
||||
import SAN_FRANCISCO from "./cities/sf.ts";
|
||||
import SOCAL from "./cities/socal.ts";
|
||||
@@ -92,6 +92,7 @@ import {
|
||||
createTeraClient,
|
||||
type FireWatch,
|
||||
type PresenceWatch,
|
||||
mergedTraffic,
|
||||
type TrafficSource,
|
||||
type WeatherWatch,
|
||||
} from "./adapters/http.ts";
|
||||
@@ -1712,7 +1713,23 @@ async function buildBoard(
|
||||
* entirely, so a deployment with a real ADS-B receiver and no marker file flew
|
||||
* the simulator.
|
||||
*/
|
||||
/*
|
||||
* One sky region per detailed source, not one circle around the board.
|
||||
*
|
||||
* `regionOf` derives its circle from the board's bounds, which is right for a
|
||||
* metro board and wrong for the merged one: 402 nautical miles centred on the
|
||||
* middle of the state, which the API refuses with `400 bad_request, "Nothing
|
||||
* this deployment serves is near 37.3,-119.25"` — correctly, since what it
|
||||
* serves is San Francisco and the Southland, five hundred and sixty
|
||||
* kilometres apart. `region` stays the board's own circle for everything that
|
||||
* wants one shape (the traffic dial, the sample generator); `skyRegions` is
|
||||
* what the live feed is actually asked for.
|
||||
*/
|
||||
const region = regionOf(entry.city);
|
||||
const skyRegions =
|
||||
ONE_CALIFORNIA && entry.id === "california"
|
||||
? UNIFIED_SOURCES.map((source) => regionOf(source))
|
||||
: [region];
|
||||
// The hand-authored corridors for *this* city. `SAMPLE_ROUTES` was passed
|
||||
// unconditionally and all of it is over San Francisco, so the SoCal board's
|
||||
// entire sky projected ~590 km off the world and rendered as nothing at all.
|
||||
@@ -1722,8 +1739,10 @@ async function buildBoard(
|
||||
// vacuum, so California keeps the honest deterministic sky while its two
|
||||
// detailed boards continue to use live ADS-B when available.
|
||||
const traffic =
|
||||
id !== "california" && access.can.liveEnvironment && access.feeds?.flights
|
||||
? tera.flights(region, routes)
|
||||
carriesMetroDetail(entry.city) && access.can.liveEnvironment && access.feeds?.flights
|
||||
? skyRegions.length === 1
|
||||
? tera.flights(region, routes)
|
||||
: mergedTraffic(skyRegions.map((r) => tera.flights(r, routes)))
|
||||
: null;
|
||||
|
||||
/**
|
||||
@@ -1781,7 +1800,29 @@ async function buildBoard(
|
||||
m.lng >= bounds.minLng &&
|
||||
m.lng <= bounds.maxLng,
|
||||
);
|
||||
const initialMarkers = id === "sf" ? [...markers, ...doors] : doors;
|
||||
/*
|
||||
* Bounds **and** metro detail — the doors' rule, plus the feeds' rule.
|
||||
*
|
||||
* The sample companies are San Francisco's, so on San Francisco's own board
|
||||
* they appear and on the Southland's they do not; on a board that contains
|
||||
* San Francisco *and draws it at metro fidelity* they appear too, which is
|
||||
* what `cities/unify.ts` needed and what `id === "sf"` silently refused.
|
||||
*
|
||||
* Bounds alone is not enough, and the budget said so within one run: the
|
||||
* coarse statewide board's rectangle contains San Francisco, so it picked up
|
||||
* forty-four markers it has no business drawing at 1,919 m to the unit and
|
||||
* went from 373 draw calls to 417. `carriesMetroDetail` is the same predicate
|
||||
* the live feeds use and it is the same question — is this a board on which a
|
||||
* building-sized thing means anything.
|
||||
*/
|
||||
const sampleMarkers = (carriesMetroDetail(entry.city) ? markers : []).filter(
|
||||
(m) =>
|
||||
m.lat >= bounds.minLat &&
|
||||
m.lat <= bounds.maxLat &&
|
||||
m.lng >= bounds.minLng &&
|
||||
m.lng <= bounds.maxLng,
|
||||
);
|
||||
const initialMarkers = [...sampleMarkers, ...doors];
|
||||
|
||||
/**
|
||||
* The two sky layers, decided here so the options object below reads as four
|
||||
@@ -2166,6 +2207,7 @@ async function presentBoard(record: MountedBoard): Promise<void> {
|
||||
|
||||
activateBoard(record);
|
||||
hideSwitchProgress();
|
||||
publishCameraHook(record);
|
||||
/*
|
||||
* Arriving is itself a reason to look ahead.
|
||||
*
|
||||
@@ -2392,7 +2434,7 @@ function activateBoard(record: MountedBoard): void {
|
||||
// the local climatology model; the detailed SF and SoCal boards keep their
|
||||
// live observations.
|
||||
weatherWatch =
|
||||
id !== "california" && access.can.liveEnvironment && access.feeds?.weather
|
||||
carriesMetroDetail(entry.city) && access.can.liveEnvironment && access.feeds?.weather
|
||||
? tera.watchWeather(entry.city.center, () => {
|
||||
updateSun();
|
||||
renderChrome();
|
||||
@@ -2550,6 +2592,89 @@ const FREE_HANDOVER = new URLSearchParams(location.search).get("handover") !== "
|
||||
*/
|
||||
const PREFETCH_ENABLED = true;
|
||||
|
||||
/**
|
||||
* Does this pack carry metro detail, as opposed to being the coarse state board?
|
||||
*
|
||||
* **Asked of the pack, not of its id**, and that distinction is a bug this
|
||||
* function exists to have fixed. Live ADS-B and live weather observations were
|
||||
* gated on `id !== "california"`, which meant "not the coarse statewide board"
|
||||
* on the day it was written and was correct then: live aircraft over a board at
|
||||
* 1,919 m to the unit are a glyph problem, and an observation from one station
|
||||
* cannot speak for a thousand kilometres of coast.
|
||||
*
|
||||
* `cities/unify.ts` then made a board that is *both* — the whole state, at metro
|
||||
* fidelity, keeping the `california` id deliberately so that the fire gate, the
|
||||
* ladder's region table and every `?city=` deep link keep working. It therefore
|
||||
* inherited a gate meant for something else and shipped with live traffic and
|
||||
* live weather silently off, which is exactly the class of defect that reads as
|
||||
* "it feels less alive" and never as an error.
|
||||
*
|
||||
* `focusRegions` is the honest predicate and needs no new field: the coarse
|
||||
* state pack declares none, and every pack that has ground worth drawing at
|
||||
* metro resolution declares at least one.
|
||||
*/
|
||||
/**
|
||||
* A camera the capture harness can plant, exposed on `globalThis`.
|
||||
*
|
||||
* **Why this exists.** Every instrument in this repo aims through a control a
|
||||
* reader also uses — `look.mjs --chapter` clicks a chapter button, `shots.mjs`
|
||||
* drives the mode dock — and that is the right default, because a harness with
|
||||
* a back door photographs a state no visitor can reach. But it means a board
|
||||
* can only be photographed *where a chapter already points*, and the merged
|
||||
* board carries California's six: the whole state, the north, two corridors and
|
||||
* two doors that leave the board. There is no rung anywhere near a city on it.
|
||||
*
|
||||
* The cost of that was three failed attempts to photograph the very thing the
|
||||
* board exists for — its cities — by clicking the minimap and guessing wheel
|
||||
* notches, each of which landed in open ocean or on empty coast. A picture is
|
||||
* this project's acceptance instrument; a board that cannot be pointed at is a
|
||||
* board whose work cannot be accepted.
|
||||
*
|
||||
* So: a seek, in the same coordinates a pack is authored in. It moves the
|
||||
* camera and nothing else — no mode change, no board change, no state a visitor
|
||||
* could not also reach by dragging. It is `globalThis` rather than a module
|
||||
* export because the harness talks to a built bundle across a page boundary,
|
||||
* and it is deliberately not wired to any UI.
|
||||
*/
|
||||
function publishCameraHook(record: MountedBoard): void {
|
||||
(globalThis as { __teraCamera?: unknown }).__teraCamera = {
|
||||
/**
|
||||
* Look at a place from a distance, in the pack's own units: degrees for the
|
||||
* target, true metres for the stand-off and the height.
|
||||
*
|
||||
* `metresPerUnit` for the horizontal and `metresPerUnit / exaggeration` for
|
||||
* the vertical, because a stand-off is a plan measurement and a height is
|
||||
* not — the same distinction `chapterStandoffMetres` and
|
||||
* `chapterAltitudeMetres` are built on, and getting it wrong is a camera
|
||||
* under the ground.
|
||||
*/
|
||||
seek(at: { lat: number; lng: number; standoffM?: number; heightM?: number; azimuth?: number }) {
|
||||
const world = record.handle.world;
|
||||
const scene = record.handle.stageScene;
|
||||
const [x, z] = world.project(at.lat, at.lng);
|
||||
const ground = world.groundAt(at.lat, at.lng);
|
||||
const standoff = (at.standoffM ?? 20_000) / world.metresPerUnit;
|
||||
const lift =
|
||||
((at.heightM ?? (at.standoffM ?? 20_000) * 0.6) / world.metresPerUnit) *
|
||||
world.city.verticalExaggeration;
|
||||
const azimuth = at.azimuth ?? 0.6;
|
||||
scene.controls.target.set(x, ground, z);
|
||||
scene.camera.position.set(
|
||||
x + Math.sin(azimuth) * standoff,
|
||||
ground + lift,
|
||||
z + Math.cos(azimuth) * standoff,
|
||||
);
|
||||
scene.controls.update();
|
||||
return { x, z, ground, standoff, lift };
|
||||
},
|
||||
board: record.id,
|
||||
};
|
||||
}
|
||||
|
||||
function carriesMetroDetail(city: City): boolean {
|
||||
return (city.focusRegions?.length ?? 0) > 0;
|
||||
}
|
||||
|
||||
function maybeHandover(record: MountedBoard): void {
|
||||
if (!FREE_HANDOVER) return;
|
||||
if (inside || fogDip !== null || record !== visibleBoard) return;
|
||||
|
||||
@@ -210,3 +210,34 @@ describe("the detail repack", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("one California is a detailed board, and the engine must agree", () => {
|
||||
it("declares focus regions, which is what the live-feed gates read", async () => {
|
||||
/*
|
||||
* Live ADS-B and live weather were gated on `id !== "california"` — "not the
|
||||
* coarse statewide board", correct on the day it was written. `unify` then
|
||||
* built a board that is the whole state AND metro-detailed, keeping the
|
||||
* `california` id on purpose so the fire gate, the ladder's region table and
|
||||
* every `?city=` deep link keep working. It inherited a gate meant for
|
||||
* something else and shipped with live traffic and live weather silently
|
||||
* off — a defect that reads as "it feels less alive" and never as an error.
|
||||
*
|
||||
* The predicate is now `focusRegions`, so this asserts the property the
|
||||
* gates depend on, and that the coarse pack still fails it.
|
||||
*/
|
||||
assert.ok((city.focusRegions?.length ?? 0) > 0, "the merged board must declare focus regions");
|
||||
assert.equal(CALIFORNIA.focusRegions ?? undefined, undefined);
|
||||
|
||||
const main = await import("node:fs/promises").then((fs) =>
|
||||
fs.readFile("src/main.ts", "utf8"),
|
||||
);
|
||||
assert.ok(
|
||||
!/id !== "california" && access\.can\.liveEnvironment/.test(main),
|
||||
"a live feed is still gated on the board id rather than on the pack",
|
||||
);
|
||||
assert.ok(
|
||||
!/const initialMarkers = id === "sf"/.test(main),
|
||||
"markers are still gated on the board id rather than on the board's bounds",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user