The CCTV frame proxy marks a Street View fallback with X-CCTV-Source, but the portable source dropped the header and get_cctv_snapshot always reported a current view credited to the camera's agency. The source now keeps the recognised provenance, and the tool labels Street View frames as historical Google imagery, refuses synthetic placeholders, and reports unknown provenance without claiming a current view.
A superseded open wait cleared the shared cancelShown slot that belonged to the newer wait, leaving its auth listener and timer alive after close; open() now settles the previous wait first. A lookup whose viewer unmounted while the Street View service loaded still sent a billed getPanorama; describe() now rechecks the lookup after acquisition.
The flights records and the mesh-floor sampler kept identical copies of the equirectangular distance; both now import src/data/approxDistance.js. The changelog entry moves to changelog.d (#787), and CURRENT-STATE notes the antimeridian behaviour.
Rebase #1142 onto current main, keeping both sides of the changelog and runtime documentation conflicts. Retain unwrapped containment and circular query coordinates.
Address review feedback on perimeterAnchorDegrees: use circular longitude for the selected outer ring, excluding its closing duplicate. Compare multipart areas along short longitude edges so a small dateline part cannot steal the card anchor from a larger polygon.
Three new card regressions fail before the fix and pass afterward. Coverage includes reversed/rotated rings, vertices at +/-180 and both multipart selection directions. Local validation: 43 focused tests; full suite 7,636 passed, one skipped, zero failures; production build, formatting, module boundaries and whitespace checks pass on Node 24.19.0. Browser tracking validation follows on the QA branch.
- i18n scanner: lastError sink, no false sinks on defaults and ternaries
- shared src/i18n/marker.js for modules that only mark strings
- wind field messages move to wind/fields.js; CITY_POIS imports from cityPois.js
- drop review IDs, change history and stale references from comments and docs
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Status pieces translate in one place (src/ui/statusText.js): a Local
ADS-B error with a single piece now translates, and the analyst card
splits empty-layer notes into pieces (Transit, Local ADS-B).
- Translate the ALPR retry chip text, the ECCC error on the Air quality
card, "Upstream response too large" and the "entry {n}" feed label.
- The unmarked-text check also sees error/loadingLabel/statusMessage/
status assignments, `status:` properties and showToast?.( /
this._showToast( calls; the scene import preview marks its pack
statuses, data and model-facing text carry i18n-ignore with a reason.
- Tests check the real code: the HUD locality formatter moves to
src/hudLocalityFormat.js, the unsaved-keys test pins the teardown.
- One copy each: city names come from src/cityPois.js, the GNSS HTTP
template and wind "field unavailable" texts; dead fallbacks removed.
- Leftovers of the reverted vessel-label change and the reformatting of
detectionHost.test.mjs / keySetup.test.mjs are back to main.
Catalogs: es/ru 2617 messages each, complete.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The vessels layer hid the detection callout for every vessel whose card
it published to the world overlay. The overlay paints only part of the
published cards (shared budget, collisions, UI chrome), so vessels whose
card was dropped lost all their text: with 60 vessels and Detection on,
21 showed only an arrow. Back to main's behaviour: the callout always
draws. Hiding it only under a painted card is HAL-628.
The translated speed unit in the callout stays.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Fixes the P1 and the confirmed P2 findings of the final review of the
i18n branch.
- CI: the air-quality model no longer imports i18n (portable module),
so check:boundaries passes again.
- Air quality layer: named in the layer panel, HUD and voice; its
Weather card, bands and errors translate. A test keeps the layer-name
table in step with the layer registry.
- Layer statuses that still reached ru/es in English: GNSS, CelesTrak,
Transit loading and feed errors, launches, perimeters, ALPR, ECCC,
wind "field unavailable", Local ADS-B streaming lines.
- Voice and HUD: preset ids show city names ("Fly to San Francisco"),
the HUD city translates, cockpit refusals cover frame, aircraft and
satellite; empty Transit notes translate on the analyst card.
- tn() keeps a caller's formatted count ("12,345 map objects").
- Cyber HUD: the language button no longer covers the bottom-right
card or the cockpit position readout.
- CCTV buttons wrap only in non-English locales; English layout matches
main again.
- Switching language asks first when Provider Settings holds unsaved
keys.
Catalogs: es/ru 2611 messages each, complete.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
MilitaryFlightRecords coerced a missing course to 0 (`courseDeg || 0`)
and a missing speed to 0 (`speedMps ?? 0`) before stickyNumber, so the
hold-last-known-good merge never ran. When an adsb.lol row arrived
without `track` or `gs`, the aircraft's icon swung to north and the
position history got a 0 kt / 0 degree fix, so dead reckoning stopped
or turned it north. The civil FlightRecords holds the last value for
the same input.
Pass the raw values to stickyNumber, with 0 as the fallback only until a
value is known, as before. A grounded row without a speed still reads
0, so a parked aircraft doesn't coast at its landing speed.
The flights ground-floor pipeline subtracted longitudes without wrapping.
approxDistanceKm, and its copy in the mesh-floor sampler, measured two
points 0.2° apart either side of 180° (21 km at Fiji) as about 38,000 km,
so low and grounded aircraft just across the line from the viewer were
never floored or mesh-sampled. corridorFloorCells walked a segment across
180° the long way round, filling its cell budget with ground behind the
contact and never requesting the cells it was about to cross, and
stickyFloorCell dropped its hysteresis for a contact on the seam. Each now
takes the short way round, and corridor points are normalised back into
[-180, 180].
SEARCH NEARBY SITES centred its Google Places search on the mean of west
and east, which for a view across 180° (west > east) is longitude 0, and
sized the radius from the view's height alone. It now measures the view's
width through 180° and searches its real centre.
Bogotá's and Santiago's PBSC feeds list depot stations in São Paulo and
Madrid as installed and renting, so activating either city drew live
docks thousands of kilometres away and counted them in the layer total.
Station information is now limited to the city's registered load radius;
every other registered feed already sits inside its radius (checked live
2026-10-16), so nothing else changes.
Adds a Bogotá/Santiago registry test matching the Brazilian and Barcelona
ones: proxy allowlist, outermost-station activation and radius reach, and
the depot filter through the real ingestion path.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The map range check floors every radius at 100 km, so the station test
passed with any loadRadiusKm up to that. get_bike_share uses the radius as
registered, so assert each system's radius reaches the stations it lists.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Conflicts:
- CCTV HUD: main's datasheet FOV, capability range and spec summary,
with their labels translated; specFovCapabilityToken takes a format
so the HUD can pass a translated one. Datasheet resolution labels are
camera data (i18n-ignore).
- Transit: main's route labels and operator mode words, with the
generic words still translated; an operator's own word stays a name.
Catalogs: es/ru 2566 messages each, complete.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Bicing (543 stations, PBSC) and AMBici (237 e-bike stations across the
metropolitan area, nextbike) join the GBFS registry from the operators'
keyless GBFS 2.3 feeds, both listed in MobilityData's systems catalogue.
- gbfs.nextbike.net joins the proxy allowlist as an exact host.
- Credits, DATA_SOURCES, CURRENT-STATE and CHANGELOG updated; a test pins
each system's proxy reachability and the range check for its outermost
stations.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Replacement buses on 5xx streetcar routes were drawn as streetcars, and
Flexity streetcars reporting no route were drawn as buses. A feed can now
supply vehicleMode(id); TTC maps 4400-4699 to streetcars and every other
fleet number to buses, falling back to the route otherwise.
Codec, product and resolution words never identify a model; generation suffixes such as Mk II no longer fall back to the base model; a mismatched manufacturer never matches, and brand-only numeric names need the brand. The datasheet FOV only fills when the source and seed give none and the pose is not curated, and DATASHEET is shown only while no calibration offset applies. Adds the CC0 extract to DATA_SOURCES.
The seven feeds publish no licence, operator or attribution fields, so DATA_SOURCES records that and credits the operator. Adds a registry test per city: allowed host and path, provider, and activation over its outermost live station.
Number() reads null, blank strings and booleans as 0 (or 1), and
/api/cctv/sources sends an unknown number as JSON null. A source-pack
camera that left out its pose therefore reached the browser as zeros
clamped to each field's floor (north, pitch -2, FOV 20, range 120 m,
mount 6 m, ground 0 m) instead of taking the defaults, and a null or
blank position put the camera at 0,0.
toFiniteNumber (server) and safeNumber (browser) now return the fallback
for absent, blank and boolean values, as validateBox already does for
Recent Imagery. The same conversion fixes the per-pack paths: a Tallinn
row with a null heading no longer reads as a high-confidence north-facing
camera, a Caltrans camera with a blank elevation keeps its 150 m ground
prior, and TfL or Catalonia cameras with a null or blank coordinate are
dropped instead of kept at 0,0 or on the zero meridian.
Guelph's feed publishes the internal database key of a route (`2991`)
where the rider sees the number on the bus (`1`), which would have put
"Route 2991" on the label a person reads. So a feed may now carry its own
`routeLabel`, the same way it may carry its own `modeWords`. Guelph's table
is its 33 routes, taken from the City's own published GTFS; an id missing
from it renders unchanged, because a raw id you can compare against the bus
beats a blank. Every other feed is identity and carries no table.
Kingston is catalogued by the City against this exact URL. Its licence PDF
link is pinned to the canonical location rather than the legacy path that
currently redirects there — Durham's entry records what happens when such a
redirect is eventually dropped.
Barrie ships REGISTERED AND OFF. The City offers its licence for acceptance
behind a click-through gate, and nobody on this project has accepted it.
Whether to accept is a person's decision, not an assumption a poller should
make, so the feed is visible, documented, and one line from enabled.
A Toronto 501 and a Helsinki 1010 are both the `tram` mode. Only one of
them is called a tram by the people who ride it, and the detection label
is documented as "what a person standing at the stop would call it".
So the mode stays shared — same silhouette, same speed limits — and a
registry entry may carry `modeWords` naming the modes it runs. Everything
without an override falls through to the shared table, so this renames one
word for one operator and nothing else.
Threading the feed to the detection metric needed a resolver in queries.js,
since the cached-contact path has only the entry. It answers from live feeds
first, so a feed disabled mid-session stops supplying vocabulary.
Resolve conflicts with main by keeping both sides:
- CHANGELOG.md: keep this PR's flights entry above main's newer entries.
- src/layers/flights/records.test.mjs: keep this PR's position-less
retention test alongside main's civil emergency-status test.
src/sources/live/aircraft.js merged cleanly: openSkySnapshot keeps main's
emergencyByIcao normalizer and passes openSkyUnpositionedId to admitRecords.
Co-Authored-By: Claude Opus 5.5 <[email protected]>