Commit Graph
430 Commits
Author SHA1 Message Date
Manjunath d18fdfa47f Merge branch 'main' into feat/voice-geometry
Picks up the HUD summary locale work (#1488). No conflicts; it changes no
voice prompt or tool description.
2026-11-03 17:31:36 +05:30
Manjunath dfdbb134d5 fix(osm): key cached place searches to the Overpass instance that answered
The /api/osm/features cache key was the query alone, kept for a day, so after
an operator repointed OVERPASS_UPSTREAMS the old instance's answers were still
served. The key now includes the configured-upstream tag, as main's other
Overpass caches check it, so a new instance is always asked.
2026-11-03 17:27:36 +05:30
Manjunath 451be8e3b7 fix(voice): treat a Zone as retired only in Nepal
Every name ending in "Zone" was kept without a level and refused as a retired
administrative identity. That is right for Nepal, which replaced its zones in
2015, but zones are current units elsewhere: Ethiopia's "Gamo Zone" was
refused. The selector now keeps the verified level unless display_name places
the zone in Nepal or names no country, and the client no longer reads "Zone"
as a retired level when the source verified one.
2026-11-03 17:27:26 +05:30
German Khokhlov 03c168d7c9 refactor(hud): share the warning line and trim the summary helpers
One provenanceLine() builds STATE | text | LAYERS for the HUD and
get_hud_caption. hasWord is one lookaround regex, capAtWord one grapheme
pass. Feed-state helpers are imported from layerSnapshot.js directly, and the
kept-whole sanitizer cases are one table.
2026-11-03 14:45:32 +04:00
German Khokhlov ab8691383b docs(hud): describe the character-only summary cap and trim comments 2026-11-03 14:34:32 +04:00
German Khokhlov 33381c5981 Merge remote-tracking branch 'origin/main' into german/hal-623-hud-summary-locale
# Conflicts:
#	src/voice/gevActions.test.mjs
2026-11-03 14:28:10 +04:00
Manjunath ecaddd838b Merge feat/voice-geometry onto main
Both stack parents (#837, #842) are on main, so the voice geometry branch
now builds on main directly. Conflict resolutions keep main's behaviour and
add the geometry work on top: osm_query gating on every provider, restored
admin identity for Nominatim outlines, merged analyst follow-up memory, and
the cancelled Globe View reset instruction ahead of the generic cancellation.
2026-11-03 14:33:34 +05:30
Sameh Khamis 64c9f4cfa5 let building words pass only on single-structure results
A building word ending the ask ('… Chapel', '… Library', '… Hall') now
passes the last-word rule only when the result is one a building ask
would accept, so a campus, zoo or district whose name merely starts the
ask (Duke University, Old Town) no longer answers it.
2026-11-02 09:07:31 -08:00
Sameh Khamis c059e12a11 merge main 17daf897 into feat/voice-outlines 2026-11-02 09:06:21 -08:00
Sameh Khamis 0712db9891 address the final review of the voice outline fixes
- A building word ("Burj Khalifa Tower", "Sagrada Familia Church") passes
  the last-word rule on a building-like result; enclosures stay out.
- The anchor chooses only among the best-named outlines, so a worse name
  never wins by containment alone.
- An ask without a quadrant takes only the quadrant of the matching street
  nearest the point; a leading quadrant ("SE Main St") may go unsaid too.
- On an unbuffered tile edge a fragment shows as an edge along the
  boundary, so a whole building touching it at a corner is not cut.
- Drop two orphaned comments and correct the place-name key wording.
2026-11-02 09:03:36 -08:00
Sameh Khamis a61d0f4c2a tighten the remaining voice outline review items
- One place-name key for server and tiles, so "St. Paul" and "Saint Paul"
  agree in Nominatim name checks.
- Tile street names: a lone letter is a direction only beside another name
  word ("E Street" is not "East Street"), and a trailing quadrant ("E St NW")
  may go unsaid in the ask.
- A building cut at the tile edge that is nearer the point than any whole
  one leaves the point instead of a farther neighbour standing in; an edge
  without a tile buffer counts as a cut, so a cut area never answers grounds.
- A batch building install re-judges only results that installed; a late
  timeout during caption conversion keeps the pending point drawn; a failed
  plain recaption keeps the old mark addressable.
- An interrupted Nominatim dispatch is reclaimed by the next lock owner ten
  minutes after the start its marker names; node:sqlite loads on first use
  without its experimental warning.
- PHOTON_URL accepts only https, which the page's connect-src allows.
- Shared OpenFreeMap tiles decode each layer when a consumer first selects
  it; outline selection reuses the shared ring area and simplification, and
  ground probes the shared ring centroid; the grounds word list lives once.
2026-11-02 08:50:05 -08:00
Sameh Khamis a38a065c5c keep bent streets, enclosed landmarks and same-name outlines honest
A street ribbon that holds neither its ring mean nor the anchor is centred
on the street's nearest point when the street runs within 100 m.

Nominatim outline selection ranks an exact name, then one holding every
asked word, then an overlap, and refuses an overlap whose name lacks the
ask's last word unless that word is in the result's address or type, so
"Central Park Zoo" is no longer Central Park. The server caches every
accepted outline and answers each ask with the one holding its resolved
anchor (sent as alat/alon), read across the antimeridian.

A duplicate mark that fails to clean up no longer tears down the new
outline it duplicates.
2026-11-02 08:37:45 -08:00
Sameh Khamis 31013d2201 Merge branch 'main' into security/cross-site-gate-overpass-military 2026-11-02 07:04:15 -08:00
German Khokhlov 645e13aeaa fix(hud): catch the UNAVAILABLE word flush against Han and keep multi-word names whole
Han and kana have no word edges, so a CJK forbidden word now counts anywhere
in the reply. The proxy no longer counts words: the model reads Rue de Rivoli
as one, so only the 80-character word-boundary cap remains.

Also restore src/voice/gevActions.test.mjs, reformatted by mistake in 818d2c82.
2026-11-02 17:13:58 +04:00
German Khokhlov 818d2c8295 fix(hud): keep localized summary words whole and drop padding
- The proxy keeps combining marks, in-word apostrophes and name dots
  (ar vowel signs, fr d'Orléans, ja ・), normalizes to NFC, caps every
  summary in characters and cuts at a word boundary.
- feedState is nullable instead of a `none` token, and the summary has at
  most five words: "exactly five" made the model pad short views with
  "no data" or "unavailable".
- The HUD caches only the model's words and adds the current warning on
  every paint; an RTL locale gets a leading right-to-left mark.
- The echo check also rejects an all-Latin reply in a non-Latin language,
  translated layer ids and, with every feed healthy, the UNAVAILABLE word;
  places are matched by word and one-word layer names are skipped in
  Latin-script locales.
- The warning tag names the worst layers first; a partial analyst card
  shows one partial chip.
2026-11-02 13:44:53 +04:00
German Khokhlov 1a6687632d Merge remote-tracking branch 'origin/main' into german/hal-623-hud-summary-locale
# Conflicts:
#	src/hud.js
#	src/hudAltitudeDatum.test.mjs
2026-11-02 11:59:08 +04:00
manjunath 62a36b9609 keep tile outlines honest when the anchor tile fails to load
A building or grounds outline from tiles now needs the tile holding the
anchor: when that tile fails and only neighbours load, no neighbouring
building or area stands in. Nominatim name tags holding several
";"-separated names match each name. Document recovery from a stuck
public-Nominatim dispatch marker, correct the phone credit comment,
drive the slow-device queue test with a mocked performance clock, and
credit GitHub handles in the changelog.
2026-10-31 02:23:43 +05:30
manjunath f32ab5446b skip Nominatim lookups when the server has none configured
Add GET /api/geocode/status ({configured}), like /api/overpass/status. The outline client and the last-resort place search ask it once per page and send no lookup a server without a Nominatim endpoint would refuse, so a default install no longer logs a 503 on its first named landmark or grounds ask. An older server or a failed probe leaves the capability unknown and lookups proceed as before.
2026-10-30 22:33:55 +05:30
German Khokhlov dbfbfcceb9 fix(hud): ask the model only with a place label, catch flush English echoes
- Skip the model when the view has layers but no place, street or nearby
  label: with layers alone it invented a place.
- The English-echo check treats only Latin letters as part of a word, so
  ids flush against kana or Han and hyphenated names are caught; it skips
  nominal, state words a locale keeps in English and names inside place
  labels.
- Outside English, per-layer state ids are left out of the request.
- The ja/zh cap steps back to the start of a Latin word, not the last space.
- Fold the CJK cap cases into hudSummaryResponse.test.mjs.
2026-10-30 20:53:31 +04:00
manjunath a71443a0ef drop the unused Nominatim outline center
The server built center from Number(row.lat/lon), which reads a missing value as 0,0, and the client never forwarded it, so the rung's second ordering point was always undefined. Order parts by the request point only.
2026-10-30 21:06:13 +05:30
manjunath 3def533d8c merge main a16eb07 into feat/voice-outlines 2026-10-30 20:54:54 +05:30
manjunath 2e82425d62 address review findings on voice outlines
- remove the unused Nominatim reserve(); spacing tests now measure the
  actual transport start across processes
- start each queued building's 2 s ground-sampling budget when it
  reaches the head of the queue, and request a frame on promotion
- accept Nominatim and grounds outlines that cross the antimeridian
- let an unnamed school, university, hospital, cemetery, stadium or zoo
  area answer a grounds ask whose head noun names that kind, using only
  the part that holds the point; compare grounds names symmetrically
- charge shared OpenFreeMap consumers their own slice and keep the
  charged budget at the previous 64 MiB
- share one place-name fold, point-in-polygon, line stitching and
  nextTask helper instead of duplicates
- exclude Who's On First sources licensed only as "CC BY (equivalent)"
  or "CC0 (equivalent)"; rebuild the pack from the pinned archives
- whole-word neighbourhood alias guard; correct the outline size-limit
  comment
- restore DATA_SOURCES.md table formatting, keeping only real edits
- test behaviour instead of private engine fields
2026-10-30 20:47:20 +05:30
Said Turksever 3a681accfa Merge branch 'main' into fix/firms-ipv4-fallback 2026-10-30 15:08:35 +00:00
Said Turksever d6c60f94b6 fix(cctv): pin A22 frame redirects to WebCamImg/ and refresh on the highway cadence
- Add A22_IMAGE_ORIGIN to the pinned frame directories, so a same-host
  redirect from www.autobrennero.it/WebCamImg/ cannot leave that directory,
  as for the other directory-pinned packs.
- Give Autostrada del Brennero a 3-minute ambient refresh in cctvLod.js,
  like the other highway packs, instead of the 5-minute default.
- DATA_SOURCES: the Open Data Hub now tags every A22 record CC0; note that
  this is the aggregator's metadata, not Autobrennero's own terms.
- Tests for the redirect pin and the refresh cadence.
2026-10-30 14:50:53 +00:00
Said Turksever 38302a27a4 Merge upstream/main into feat/cctv-a22-autobrennero
Resolve conflicts with the NYC, Toronto, Lithuania, Florida, Taiwan and
Kartverket work on main. The CHANGELOG entry moves to
changelog.d/956-a22-brennero-webcams.md, as main now asks.
2026-10-30 14:50:41 +00:00
Said Turksever df01964171 fix(firms): keep the IPv4 retry from crashing the server; guard the call sites
- fetchIpv4 builds its Response inside the https response callback, outside
  the promise. A 204, 205 or 304, a status above 599 or an invalid reason
  phrase made the Response constructor throw there, an uncaught exception
  that stops the dev server. Null-body statuses now get a null body and
  anything else that cannot become a Response rejects, as the Radio Browser
  transport does.
- A non-OK FIRMS or mapkey-status response cancels its body so the IPv4
  socket closes at once instead of at the deadline.
- Tests: the crash cases (fail on the old code), a source check that every
  upstream request goes through fetchFirms and that fetchSource's body read
  shares its deadline (fails if either call reverts to fetch), a real-fetch
  contract test for the address-selection error shape, and an explicit skip
  in the IPv4-only socket test where the host cannot tell the families apart.
- Changelog entry moves to changelog.d/1078-firms-ipv4-fallback.md per
  CONTRIBUTING; CURRENT-STATE says which timeouts are retried and that the
  retry does not follow redirects.
2026-10-30 14:50:27 +00:00
Said Turksever bae3433b24 Merge upstream/main into fix/firms-ipv4-fallback
Resolve fetchSource onto main's shared deadline: one AbortSignal covers the
fetchFirms request and the capped body read. The CHANGELOG entry moves to a
changelog.d fragment in the next commit.
2026-10-30 14:50:27 +00:00
manjunath 578ebdc030 merge main f13c60c into feat/voice-outlines
reconcile voice outlines with main f13c60c, retaining German/Japanese,
Operator HUD retirement and Context/Radio cleanup, named-building
containment, courtyard-hole, non-Latin identity, attribution, cancellation
and antimeridian repairs

keep outline callouts above the open voice preview when an above-panel
slot fits without colliding with another callout,
and clip the compact dock location label on narrow screens
2026-10-30 19:02:47 +05:30
German Khokhlov 7713fb8ae8 fix(hud): keep English out of localized summaries, cap ja/zh by characters only
Second follow-up review fixes:

- Japanese and Chinese summaries are capped at 20 characters only, without
  the five-token cut first, and the cap steps back to a space instead of
  splitting a Latin word.
- The HUD request sends localized layer names in feedProvenance too and
  leaves the English narration note out outside English. A non-English reply
  that still echoes a feed-state id or a translated English layer name falls
  back to the deterministic line.
- A camera move during typing shows the deterministic line, not a fragment.
- A view with no place labels and no enabled layer does not ask the model.
- Behaviour tests on IntelHUD replace the regex checks of hud.js; docs and
  the instruction wording updated.
2026-10-30 16:28:56 +04:00
German Khokhlov 7b223d7d7b fix(hud): state word first, layer names last; CJK cap by locale
Follow-up review fixes:

- The HUD line is STATE | text | LAYERS for the AI summary and the
  fallback line, so the narrow minimal and cyber layouts show both the
  warning and the summary. get_hud_caption builds its caption the same
  way. The unused "{state} {layers}" key is pruned from the catalogs.
- The 20-character cap applies only when the request locale is Japanese
  or Chinese; other languages keep five words around a Han place name.
- enabledLayers names are localized too, and the instructions name layers
  only from enabledLayerLabels, never from feedProvenance or its note.
- The keyless test restores GEV_RATELIMIT_OPENAI_PER_MIN again; comments
  and docs updated.
2026-10-30 14:27:59 +04:00
German Khokhlov f967218a04 fix(hud): lead with the state tag, keep feedState in get_hud_caption
Review fixes for the HUD summary language change:

- The translated feed-state tag now leads the one-line summary and the
  fallback line, so the readout's ellipsis cannot hide it.
- get_hud_caption checks the reply's feedState, returns it and appends the
  state tag; a reply naming another state keeps only the place.
- The model gets the layer names the user sees (localizeLayerName).
- Japanese and Chinese summaries are capped at 20 characters; pt, zh-CN and
  zh-Hant get explicit language names.
- A partial view is narrated as incomplete coverage, not as not live.
- provenanceTag and hudSummaryMatchesProvenance move to layerSnapshot.js so
  the tools package can use them without browser globals.
- docs/CURRENT-STATE.md, changelog and comments updated; redundant tests
  trimmed.
2026-10-30 13:06:53 +04:00
German Khokhlov 563df3bad9 fix(hud): AI summary in the UI language, canonical feed state, partial aggregation
The HUD sends its locale with the summary context; the proxy names that
language in the instructions and the input, English when missing or
unsupported. The model returns {summary, feedState}; the HUD shows the
summary only when feedState matches its own state for a view that is not
nominal, and appends its own translated state tag.

partial joins the shared feed-state table between fallback and nominal,
so one partial layer no longer reads off and partial plus nominal no
longer reads nominal.
2026-10-30 12:37:43 +04:00
Said Turksever adb21d098d Merge branch 'main' into fix/remove-operator-hud-layout 2026-10-29 14:22:01 +00:00
Said Turksever 39a60b4034 Remove the Snow visual preset
Snow is no longer offered anywhere a style can be chosen: the Visual
Presets tray, keyboard shortcut 7, the Cockpit vision carousel, and the
set_visual_style voice action. The shader and its labels go with it;
weather snowfall and the SNOW weather condition are unaffected.

Share links keep working. Snow's enum code (6) stays reserved, so a
compact or long-form link that names it opens on Normal and drops the
Snow shader parameters without reporting them as unknown. A Scene
Director shot saved with Snow plays on Normal too. Snow's frozen share
defaults matched Normal's apart from those parameters, so no other
setting in an old link changes meaning.

The legacy voice-schema pins restore Snow before hashing, so the
unchanged pins still prove nothing else moved; the complete Realtime
payload digest is re-derived.
2026-10-29 11:20:49 +00:00
Said Turksever 8b2c699370 Remove the Operator HUD layout
Display > HUD > Layout and the set_hud voice action now offer Tactical,
Minimal and Cyber. The Operator option, its CSS and its QA coverage are
removed, and the unused "Operator" translations are pruned.

Share-link codes are append-only, so operator keeps its hudVariant code.
A link, scene or saved state that names it restores the default Tactical
layout. The voice schema pins keep their legacy digests by restoring the
retired value before comparing; the full-payload digest is re-derived.
2026-10-29 10:41:58 +00:00
Sameh Khamis c1f60cb7e7 Cut the Google requests the HUD summary makes on its own
The HUD builds place context for its AI summary whenever the camera
settles, and each build paid for up to four reverse geocodes plus a Nearby
Places search, even when no OpenAI key was configured to use them.

- Ask GET /api/openai/hud-summary/status once; with no summary configured,
  or after an unconfigured reply, make no place lookups for the page.
- Reverse-geocode at most two points: the view center and one viewport
  point.
- Reuse a lookup until the view center moves a quarter of the visible
  width, the camera's distance to it doubles or halves, or the camera
  crosses a lookup height. The reused points are asked again, so only a
  timeout, failure or empty answer spends.
- Repaint the last AI reply when a small pan leaves the context unchanged.

Cached-only hosts and voice context lookups are unchanged.
2026-10-28 14:59:33 -07:00
quanticsoul4772 3e5edff884 Merge branch 'main' into upstream/terrain-429-pause 2026-10-28 09:05:56 -07:00
Said Turksever c1820aea49 fix(terrain): end retries early on a long Retry-After; cover the 429 pause
A Retry-After longer than the 10 s retry budget used to sleep the whole
budget out and then give up, so the proxy's 429 pause started 10 s late
and every new-point poll in that window still went upstream and logged.
The retry loop now stops at once in that case.

Tests: the retry loop no longer sleeps for an unreachable Retry-After;
fully cached points, including stale ones, are served during the pause
with no upstream call; a 503 does not pause; a shorter concurrent
Retry-After never cuts the pause short. CURRENT-STATE now says which
requests are still served and which log.
2026-10-28 14:09:12 +00:00
quanticsoul4772 ea491e1603 Merge branch 'main' into upstream/perimeters-stale 2026-10-27 16:51:15 -07:00
quanticsoul4772 0ba59112f9 Merge branch 'main' into upstream/terrain-429-pause 2026-10-27 16:51:00 -07:00
manjunath d4434aa6d7 feat(outlines): restore voice outlines without public Overpass
use bundled place boundaries and shared OpenFreeMap tiles before a guarded Nominatim fallback

preserve multipart shapes, holes and cancellation,
and keep pending annotations visible while ground sampling finishes across frames

keep non-Latin name distinctions when selecting provider results,
and retain an outline anchor only when it lies in filled geometry
2026-10-27 13:24:02 +00:00
Sunil56224972 accb8983ca fix(security): add cross-site gate to military-installations proxy
The /api/military-installations endpoint was the last keyless proxy without
the admitSameSite gate that protects terrain, CCTV, traffic, places, and
Celestrak. A cross-site <img>, foreign Origin, opaque origin, or
reverse-proxy-forwarded request now receives 403 before any Overpass query.
Same-origin app requests and bare tool requests continue to work.

Adds 4 integration tests (cross-site refused, same-origin admitted,
bare tool admitted, proxied refused) following the terrainHeightsBounds
test pattern.
2026-10-27 18:21:53 +05:30
Sameh Khamis c533b1994c Merge main and preserve voice panel and GhostMaps schema coverage 2026-10-26 08:52:03 -07:00
Sameh Khamis aeee3652ce Merge PR #1299 with current main for validation 2026-10-26 08:39:16 -07:00
Mazeyar Moeini Feizabadi 4da002bd42 Merge current main into S2 GhostMaps and preserve updated import and voice behavior 2026-10-26 16:25:49 +01:00
Mazeyar Moeini Feizabadi 4a18af5426 fix: address GhostMaps resource and source ownership review findings 2026-10-26 16:24:34 +01:00
quanticsoul4772 c53928ab06 Merge branch 'main' into upstream/perimeters-stale 2026-10-25 19:45:35 -07:00
Jenil Patel a7fcb3c232 fix(maps): avoid 404 on keyless Google tiles-token probe (#1066)
Return an uncached unavailable-token response for keyless Google tile-token requests.

Contribution by @dvilrgamerz.
2026-10-25 19:13:38 -07:00
quanticsoul4772andClaude Opus 5.5 25973ade2c fix(perimeters): report a stale WFIGS snapshot as stale, and stop serving it after a day
When WFIGS was unreachable the proxy served its last snapshot, marked stale
(X-Data-Stale, body.stale), with no age limit, and the client source kept
only the rows. The layer then read healthy with a fresh update time and
get_fire_perimeters reported the perimeters as current; three days into an
outage it still said "1 mapped wildfire perimeter in the requested box."
The source now offers getSnapshotDetail ({rows, stale, fetchedAt}); the
layer reports stale with the snapshot's fetch time, the tool adds stale,
retrieved_at and "(data may be stale)", and the proxy serves a stale
snapshot for at most 24 hours, as the GNSS proxy caps its own.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 18:01:19 -07:00
quanticsoul4772andClaude Opus 5.5 923211c24a fix(terrain): key the 429 pause on status, never shorten it, and document it
Review follow-ups: the upstream error now carries its HTTP status and the
pause checks error.status instead of the message text; concurrent 429s
extend the pause with Math.max rather than a shorter Retry-After cutting a
longer one short; the per-chunk re-check says it is for multi-chunk
requests; the first 429 test runs its backoff on mocked timers.
CURRENT-STATE describes the pause.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 17:08:26 -07:00