Commit Graph
1491 Commits
Author SHA1 Message Date
German Khokhlov 3a78f40024 Merge main into german/transit-bikeshare-empty-state
Conflict in src/layers/transit/queries.js: keep the branch's shared note with the gate's enter altitude and main's distinct region count.
2026-11-06 20:00:58 +04:00
German Khokhlov 910e63a56a Merge main into german/vessel-callout-under-card
Resolve addPaintItem by keeping both the collision reset from main and the
queued-card frame stamp from this branch.
2026-11-06 20:00:45 +04:00
German Khokhlov e1ea524b68 Merge main into german/space-missions-failed-entry 2026-11-06 20:00:21 +04:00
German Khokhlov ea22d16c1a Merge branch 'main' into exp/cyclone-shared-context 2026-11-06 19:44:54 +04:00
German Khokhlov 4e518821b5 fix(cyclones): name the classification and mark a stale cache in shared context
- Publish classificationName next to the raw NHC code; unknown codes stay
  unexpanded.
- Publish staleCacheFetchedAt only while the proxy serves its cache.
- Touch the shared store on clear only after this layer published, so a
  feed failure no longer evicts another layer's dangling selection.
- Drop the unreachable no-storm branch and the unused return value.
- Tests: split the heading fixture into due north and stationary, cover
  the unavailable and failure paths with the real store, and check that
  clear/disable leave another layer's selection alone; fold the fake-store
  test into the real-store one.
2026-11-06 19:43:04 +04:00
Said Turksever 15fdf65a73 Merge branch 'main' into perf/fleet-tick-skip-hidden 2026-11-06 14:52:56 +00:00
German Khokhlov aca5317a2a Merge branch 'main' into exp/cyclone-shared-context 2026-11-06 16:03:13 +04:00
Said Turksever 0dbbd9047e Merge remote-tracking branch 'upstream/main' into HEAD 2026-11-06 11:54:29 +00:00
Said Turksever acc4e63ec4 Merge branch 'main' into fix/keyless-unicode-search 2026-11-06 11:53:32 +00:00
Denis Groshev 2e87dd87eb Merge branch 'main' into denis/gev-news-layer
Wildlife Sightings (#1591) published share token 9, so News takes the
next free token, 00. The token tests read the ledger before both where
they were written against it, and the README counts both layers.
2026-11-06 12:33:13 +01:00
Denis Groshev 61424e4256 fix(news): keep a refused key refused during a slow read, and read Local when Conflicts fails
A slow re-read of a refused key read as unavailable until it landed; it
now stays refused. The first-read wait is 10 s, for a margin under the
browser's 15 s. A failed Conflicts read no longer stops Local's refresh,
which the server reads on its own. Tests cover GDELT's wait, the refused
key and a caller abort past the timeout, and fail rather than hang; the
docs say what a section serves meanwhile.
2026-11-06 12:02:58 +01:00
Denis Groshev c6ae4c44d7 fix(news): answer within the browser's wait on a first read
A country's first World News API read, or Liveuamap's, could take up to
20 s while the browser waits 15, so the panel showed the browser's own
"signal timed out". A read with nothing to serve yet is now waited for
at most 12 s, as GDELT's already was: past that the section answers
unavailable while the read goes on, and the next refresh is served from
it. A client timeout reads "News feed unavailable".
2026-11-06 11:41:37 +01:00
Itallo BrandãoandClaude Sonnet 5.5 433b336c2d feat(transit): add Szczecin buses and trams (ZDiTM, CC0)
Keyless GTFS-Realtime feed published by ZDiTM Szczecin under CC0 1.0.
Speeds are m/s (checked against vehicle movement), the file refreshes about
every 20 s, and the feed carries no route ids, so vehicles take the default
bus mode.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-11-06 02:50:42 -03:00
Sameh Khamis 93d495b0e5 Merge branch 'main' into pr/wildlife-sightings 2026-11-05 17:24:06 -08:00
Sameh Khamis d807c3007e Merge branch 'main' into pr/wildlife-sightings 2026-11-05 17:15:10 -08:00
Sameh Khamis fcad75a7b6 Merge remote-tracking branch 'origin/main' into fix/globe-free-look-orbit
# Conflicts:
#	src/cameraVerbs.js
2026-11-05 17:08:07 -08:00
Sameh Khamis 4951393997 Keep the place in view when a late zoom out catches a tilt
From 400 km, a tilt to -5° that a zoom out x2.5 caught 70 frames in eased down from the camera's old pitch at the new range. That put the camera below the place's horizon: the first frame's crosshair hit the ground 186 km from London, and London stayed hidden for about 11 frames. The re-solve also left the pivot pitch at 0°, so a zoom in before the next frame computed an infinite clearance floor, was refused, and stayed at 1,000 km.

The re-solved pivot pitch now stops at the place's horizon limit, or where the pivot already was. A camera that the zoom leaves past that limit steps down to it with the zoom and holds it, and the zoom still reports that angle. A zoom in straight after brings the range back to 400 km.
2026-11-05 16:55:54 -08:00
Sameh Khamis 3438a88cc7 Ease a late zoomed tilt to its new limit instead of jumping there
From 400 km, a tilt to -5° that a zoom out x2.5 caught at -8.0005° reported -8°, and the next frame jumped to -9.407° and ended there. The zoom kept the camera's pitch as the goal when it was already past the new range's horizon limit, but at the same pivot pitch the longer range looks down more steeply, so the next lookAt dropped the camera 1.4° at once.

The zoom now re-solves the pivot pitch so the new range keeps the camera's pitch, and aims the tilt at the asked angle or the new limit, even when that limit is below where the camera stands: the tilt eases down to it. The zoom's reply names that end, and the camera reaches it with no frame moving more than 0.1°.
2026-11-05 16:31:46 -08:00
Sameh Khamis 42fa974ee3 fix(wildlife): keep each failed source's retry timing after a partial failure
A partial failure reset the layer's cooldown, so a camera move retried at
once. Acartia's error was discarded, an absent X-Upstream-Status hid the
HTTP 503 (the proxy's daily-budget reply), and a grid schema error masked
the observation 503. Each failed source now keeps its status and
Retry-After, the HTTP status counts when no upstream status is sent, and the
layer waits for the longest 429/5xx cooldown among them. The shown error is
the one that explains the cooldown.
2026-11-05 16:27:19 -08:00
Sameh Khamis f332150689 fix(camera): hold the globe recovery until every pointer is released
The held-pointer guard was one flag, so with two fingers down, lifting one cleared it and the recovery turned the view down under the other (pitch -42° to -90°). It now tracks each pressed pointer by id and defers until the last is released.

A release outside the window that the page never sees could leave the recovery deferred for good. A lost window focus, a hidden page or a lost pointer capture now releases every held pointer, and a pointer that moves with no button down is released.
2026-11-05 16:16:05 -08:00
Sameh Khamis 6479167b50 Pivot a tilt at exactly 1,000 km and report where a zoom now ends it
A pivot range rebuilt from the camera's position came back a hair over the 1,000 km cutoff when the view sat exactly on it, so a tilt from 1,000 km ran in place and lifted the crosshair onto the sky. The cutoff now allows 1 m of slack.

A zoom during a tilt to an angle changes the range the pivot holds, and with it the place's horizon limit, but the tilt kept its old goal and its reply its old angle: from 400 km, a tilt to -5° zoomed out x2.5 reported -5° with no note and ended at -9.4°. The zoom now re-judges the goal at the new range, eases the tilt from where it is to it, and its result names the angle the tilt now ends at, with a note.
2026-11-05 16:14:27 -08:00
Sameh Khamis fb0a58ef3c docs(wildlife): cite the documented iNaturalist UTFGrid endpoint and Acartia's key request
/grid/{z}/{x}/{y}.grid.json is documented in the v1 and v2 API docs as
Grid Tiles UTFGrid; only its per-cell records are unspecified, which is
what the schema guard covers. DATA_SOURCES.md now also notes that
Acartia's README asks API users to create an account and an API key,
although /sightings/current answers without one today.
2026-11-05 16:07:48 -08:00
Sameh Khamis 5391687d46 fix(wildlife): draw what arrived when one sighting source fails
An iNaturalist rejection discarded a successful Acartia reply, and the
antimeridian Promise.all lost both halves when one failed. Each box now
settles independently; the failed part is reported on
sources.inaturalist (error and failed boxes), the layer keeps that
area's last iNaturalist rows and shows DEGRADED with retry timing, and
the update fails outright only when every requested source failed.
2026-11-05 16:06:41 -08:00
Sameh Khamis 3cb30c3f97 fix(wildlife): point the Acartia card link only at acartia.io
The card's "Acartia" link was built from the contributor-supplied
photo_url, so any https site could appear labelled as Acartia. Acartia
has no documented per-sighting page, so the source link is now always
the Acartia site, on the server projection and again in the card.
The separate "Open on Acartia" fallback link is no longer needed.
2026-11-05 16:05:02 -08:00
Sameh Khamis 82138478d0 fix(wildlife): treat a valid empty Acartia snapshot as a fresh success
A quiet or fully filtered feed raised invalid_snapshot, so the proxy
answered 502 with a 15 s cooldown and re-polled about four times a
minute. Only a non-array payload is malformed now; an empty projection
caches for the normal ten minutes and clears earlier rows.
2026-11-05 16:03:52 -08:00
Sameh Khamis bd99000433 Merge remote-tracking branch 'origin/main' into pr/wildlife-sightings 2026-11-05 16:00:37 -08:00
Sameh Khamis 44106b2bfb fix(camera): hold the globe recovery while a pointer is down
Holding a drag still for half a second on a view that already showed no surface looked like a camera at rest, so the recovery turned the view down under the user's hand. The recovery now defers while a pointer pressed on the canvas is held, and runs once it is released, as for a flight or a playing scene.
2026-11-05 15:55:52 -08:00
Sameh Khamis f53342932d Merge branch 'main' into fix/globe-free-look-orbit 2026-11-05 15:52:21 -08:00
Sameh Khamis dae95e1c7f Refuse a motion after its reply's fly-to found nothing, also on Gemini
Gemini runs one turn's calls one after another. By the time "pan left" ran beside "fly to Xyzzyville", the lookup had already found nothing, so there was no flight to wait on and the pan moved the old view with ok: true. OpenAI's parallel calls refused the same reply.

The runner now remembers, for the latest reply that sent a voice fly-to, whether one moved the camera and whether one found nothing. A tilt, orbit, pan or rotate of that reply with no flight left to wait on is refused when its fly-to found nothing and none moved. The reply is Gemini's turn, passed as a per-turn reply object, or OpenAI's authorityGroup. A motion in a later reply, or beside a fly-to of the same reply that did land, runs as before.
2026-11-05 15:51:14 -08:00
Sameh Khamis 1eef14454a Drop a queued voice motion when another navigation takes the camera mid-flight
A motion queued behind a voice fly-to checked only that its reply was current and that the user had not touched the map. A location-panel search, share link or file import stamps a deferred navigation without stopping the flight, so the flight landed, the motion took navigation, and the search's reassert then failed: the search was silently dropped while the camera kept orbiting.

The runner now counts camera handoffs from subscribeCameraHandoff, less the ones voice fly-tos make themselves, and each voice flight records that count when it starts. A motion whose flight saw another navigation since then is not run and says so. Voice fly-tos' own stamps do not count, so a later fly-to in the same reply, including a lookup that finds nothing, is still followed as before. The test harness now publishes handoffs and stamps its voice lookups, as the shell does.
2026-11-05 15:48:21 -08:00
Denis Groshev 427463cc45 fix(news): list Local newest first
Local ranked its reports by severity first. A country's own news now
carries no severity, so in a conflict area GDELT's reports (severity 1
and up) could crowd every one of its stories out of the 40 listed.
Local is now newest first; severity still shows by colour.

Also: readTitle reads Conflicts headlines only, the economy category's
comment and the attribution popover name World News API's category,
and KNOWN-ISSUES names Core's ids for World News API's categories.
2026-11-06 00:45:33 +01:00
Denis Groshev 82057cbb51 fix(news): keep World News API's own category for a country's news
The bundled rules read fighting and crises; in everyday headlines their
words mislead ("Kazakhstan Advances in Global Digital Rankings" read as
ground fighting). A country's own stories in Local now keep World News
API's category (politics, business, else other) and carry no severity.
Fighting in the area still shows through the Conflicts reports placed
there.
2026-11-06 00:45:33 +01:00
Denis Groshev 1e78ac931c Blame a GDELT export only while GDELT answers, and fix the review's notes
An export is given up on (never published, unreadable, or failing three
times) only while GDELT itself answers: its list of exports read, or
another export of the same round read. An outage that answers 404, or junk,
for everything now gives up on nothing, and a failing file earns one strike
a round rather than three within the first seconds' rounds.

Docs: News's share token is 9; territories without a country code are named
as themselves too; the changelog fragment credits one pull request. Unused
exports dropped from the rules and stale scaffolding from the ledger tests.
2026-11-06 00:45:33 +01:00
Denis Groshev a5f9870179 Document the News layer's own sources, keys and limits
DATA_SOURCES, the README's layer and key tables, CURRENT-STATE and the
changelog describe the News layer as it now is: a configured news server,
or Core's own reading of GDELT (no key), Liveuamap (optional) and World
News API (Local, free plan backlink credited). .env.example gives the
download sizes and the daily read budget; KNOWN-ISSUES lists what machine
coding gets wrong and which disputed areas are named as themselves.
2026-11-06 00:45:32 +01:00
Denis Groshev 5bb489d1fb Put news on the globe, with a feed panel in the right rail
Events ▸ News draws the last 24 hours of reports from curated hotspots
(Ukraine–Russia, Israel–Gaza–Lebanon, Iran–Hormuz, Yemen–Red Sea, Sudan,
Sahel) and developing situations elsewhere, from any server that answers the
`/api/news` read routes.

- Globe: one marker per merged event, clamped to the ground and culled at the
  horizon; one beacon per hotspot when zoomed out and a pulsing beacon for a
  developing situation; hotspot outlines with disputed areas dotted and
  labelled by who administers and who claims them; picture cards for at most
  ten major or fast-growing events with two or more sources, never
  overlapping, switchable off.
- Panel: hotspot chips, a severity filter (significant and above by default),
  categories, minor news off by default, and a scrolling list of event cards
  with picture, headline, place, sources, age and the sides that reported it.
  "In view" lists what is near the map below 3,000 km once the camera
  settles. A card flies the globe to its event and opens it with a link to
  the publisher. Reduced motion stops the pulse and the flights.
- Core serves no news itself: the local server proxies GEV_NEWS_ORIGIN when it
  is set, and answers 503 unavailable otherwise, so the layer reads "not
  configured" once instead of retrying.
- Share token 9 (enabled-only); voice stays off for this layer.
2026-11-06 00:45:24 +01:00
Denis Groshev dd83812a21 Hold Cockpit regional news to the last 24 hours, and tell its states apart
Regional News showed "REGIONAL NEWS UNAVAILABLE" above populated rows and a
static "RECENT" footer over months-old articles. The status banner kept
`display: grid` when hidden, every non-empty answer carried the unavailable
text, and nothing limited or sorted articles by age.

- One window (regionalNewsWindow.js, 24 h): the local proxy asks Google News
  with `when:1d` and GDELT for 24 h, drops undated, older or future-dated
  articles, sorts newest first, and reports newsWindowHours/newsFetchedAt.
- The Cockpit labels four states: fresh (banner hidden, "LAST 24 H"),
  kept after a failed refresh ("CACHED · REFRESH FAILED"), no news in the
  window, and unavailable. The footer lives in the news state, so it
  survives page and tab changes, and the client drops out-of-window rows.
- `.cockpit-brief-status[hidden]` now hides the banner.
2026-11-06 00:45:19 +01:00
Sameh Khamis c4910d24d0 Keep the place centred when a far tilt reaches the horizon
From 550 to 1,000 km of range the camera's -5° limit lies past the place's own horizon. The swing ran into its 150 m clearance, let go of the pivot and tilted the rest in place, which lifted the crosshair onto the sky (28 to 63 km up from 600 to 900 km), and a return to top-down then landed hundreds of km from the place.

The swing now hands over to an in-place tilt only where the clearance is what stops it (within about 17 km). Farther out it stops with the camera 0.5° above the place's horizon, still pivoting: a tilt to an angle reports the angle it reached with a note, a continuous tilt stops there, and a further tilt up is refused as at the limit. Tests check that the crosshair stays on the place, frame by frame for a continuous tilt, and that top-down returns over it.
2026-11-05 15:43:51 -08:00
Sameh Khamis 8687512fc8 Merge branch 'main' into manjunath/hal-695-voice-tilt
Re-derive the Realtime schema pin for main's control_cockpit wording and this branch's pitchDeg.
2026-11-05 15:37:50 -08:00
Said Turksever d7856109c7 Merge branch 'main' into fix/keyless-unicode-search 2026-11-05 22:08:58 +00:00
Yehe Liu 4423f4b4a6 Merge branch 'main' into pr/wildlife-sightings 2026-11-05 17:04:06 -05:00
Sameh Khamis e3f668831c Merge branch 'main' into denis/gev-cockpit-entry 2026-11-05 14:01:31 -08:00
Sameh Khamis 63fd559496 Keep the ridden aircraft's layer when Contacts ends, and clear its rows from Live Signals
Riding an aircraft now adopts its layer the way a direct selection does, and
Contacts gives up a dependency the user adopts, so ending Contacts mid-session
(one of its layers off, or Contacts itself) no longer turns off the ridden
layer and ends the Cockpit. When Contacts goes off, Live Signals drops the
rows built from its snapshot instead of leaving stale distances marked
CURRENT, and the feed-off warning is no longer duplicated.
2026-11-05 14:01:17 -08:00
Said Turksever bd8ef09042 Merge branch 'main' into fix/keyless-unicode-search 2026-11-05 21:44:18 +00:00
Sameh Khamis a75b495cf9 Merge branch 'main' into fix/chat-provider-switch-keeps-context 2026-11-05 13:43:40 -08:00
Yehe LiuandClaude Opus 5.5 14f88b3e08 feat: Wildlife Sightings layer from iNaturalist and Acartia
Recent community wildlife observations, as a new Wildlife group in the
layer panel.

- Server: keyless iNaturalist proxy (v2 observations with only the
  projected fields; undocumented v1 UTFGrid density tiles, decoded on the
  server) sharing one paced queue (burst 4, ~1/s, 60/min, 8,000/day budget,
  up to four in flight), in-memory caches and upstream-only cooldowns;
  Acartia Salish Sea marine-mammal feed rounded to 0.01 degrees with
  comments dropped.
- Layer: grid counts drawn as a soft view-ranked density glow; real sampled
  sightings as taxon badges at their true positions with ambient photo
  thumbnails and labels; obscured records stay privacy cells; a clicked
  sighting stays pinned through camera moves and refreshes.
- Anchored photo card per selection with the single iNaturalist link;
  attribution in the layer row and the Data attribution popover.
- Filters (CONFIRMED, taxa presets) round-trip in share links with token 9.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-05 16:17:12 -05:00
German Khokhlov 7f8556c691 Merge branch 'main' into exp/cyclone-shared-context
# Conflicts:
#	src/app/constructCatalog.js
2026-11-05 23:01:23 +04:00
quanticsoul4772 d0bf21b8c3 Merge branch 'main' into upstream/tools-heading-wrap 2026-11-05 10:23:22 -08:00
German Khokhlov 017a3bc99c Merge branch 'main' into feat/rio-transit-gtfs-rt 2026-11-05 21:21:13 +04:00
German Khokhlov 90db4eb2c9 Name the real gate altitude and repaint coverage rows at once
The Transit prompt said "Fly below 3,000 km", but the closed gate opens at
2,850 km; it now names the enter threshold, as Bike Share does. When the
camera changes coverage, Transit and Bike Share ask the Layers panel to
repaint instead of leaving the old prompt up until the next 15 s / 60 s tick.
2026-11-05 21:21:03 +04:00
German Khokhlov da00b096d2 Fade a vessel's callout by its card's painted opacity
The callout now asks for the opacity its own card paints with this frame,
keyhole fade included, and fades out as the card fades in. A card faded out
at the keyhole rim leaves the callout readable, and a card fading out after
leaving its source still hides it. The vessel card id is cached on the
record, and the allocation gate covers the lookup.
2026-11-05 21:21:02 +04:00