Commit Graph
308 Commits
Author SHA1 Message Date
Rudy CelekliandClaude Sonnet 5.5 29583c55ed fix(firms): reject impossible acquisition days in CSV parsing
Rebased onto current main with review follow-ups folded in.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-14 20:12:29 -04:00
Rudy Celekli 5a14a06a52 docs: address maintainer review for PR #1044 2026-10-14 20:12:08 -04:00
Rudy Celekli 8b68ff8412 fix(firms): reject missing and out-of-range detection coordinates 2026-10-14 20:12:08 -04:00
Sameh Khamis 51d335b1db test: check the route cap at exactly 200 turns
The existing "route that fits" case used 199 steps, which is how the
off-by-one went unnoticed. Folds the docs note into the existing cap sentence
and makes the changelog entry specific.
2026-10-14 16:35:10 -07:00
Sameh Khamis 7cc6199245 Merge branch 'main' into contrib/gods-009-route-cap-truthfulness-20261011-reviewed
# Conflicts:
#	CHANGELOG.md
2026-10-14 16:34:45 -07:00
Sameh Khamis 5be2185dc7 fix(weather): treat a missing code as unavailable in cloud effects too
Number(null) is 0, so the cockpit cloud profile treated a missing weather code
as clear but available. The briefing's three checks now share one helper, and
the current-state note is its own bullet instead of folding into the route one.
2026-10-14 15:06:52 -07:00
Sameh Khamis a7e5f341ab Merge branch 'main' into contrib/gods-006-weather-missing-observations-20261011-reviewed 2026-10-14 15:03:20 -07:00
Ian BlenkeandSameh Khamis 504d56ba2b test: fix flaky timing and timeout guards (#969)
Clears the timeout guards once each race settles, measures the 15,000-vehicle transit ingestion with main-thread CPU time instead of wall time, and times the region-timeout case from the boundary lookup with a 2 s ceiling, below the 3 s default budget, so an ignored budget still fails.

Co-authored-by: Sameh Khamis <[email protected]>
2026-10-14 14:58:53 -07:00
Rudy Celekli a140c52f84 fix(directions): report truncation only when a maneuver was actually omitted 2026-10-14 14:17:52 -04:00
Rudy Celekli c86c1a4cce fix(weather): keep absent observations unknown instead of reporting clear skies 2026-10-14 14:17:48 -04:00
Mazeyar Moeini Feizabadi 01a8ad7aa7 fix: address GNSS integrity and aircraft emergency review findings 2026-10-14 17:43:13 +02:00
Mazeyar Moeini Feizabadi 4240d04642 Merge current main into HAL-522 review candidate 2026-10-14 16:53:13 +02:00
Mazeyar Moeini Feizabadi 767a7d5ae8 perf(import): reuse generated pin textures and trim unused processing 2026-10-14 15:01:47 +02:00
Said Turksever 40be3bc54d Merge branch 'main' into fix/nyc-cctv-pack 2026-10-14 12:52:49 +01:00
Mazeyar Moeini Feizabadi c58ff5c215 fix(import): keep KML points visible when remote icons are blocked 2026-10-14 13:16:10 +02:00
Said TurkseverandClaude Opus 5.5 128a689a56 fix(cctv): make the NYC DOT pack opt-in and carry DOT's disclaimer
NYC DOT asks developers who use its camera feed to sign a data-sharing
agreement, and this project does not hold one that covers downstream
installs. The pack now loads only when CCTV_NYC_ENABLED=1; unset, empty
or any other value makes no request to webcams.nyctmc.org (tested).

The NYC credit carries NYC DOT's requested application disclaimer
verbatim, and DATA_SOURCES, README, CHANGELOG, CURRENT-STATE and
.env.example describe the prerequisite.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 11:44:25 +01:00
ulihhhh b57f2ded7f Merge remote-tracking branch 'upstream/main' into pr595-sync
# Conflicts:
#	README.md
2026-10-14 10:14:36 +02:00
Mazeyar Moeini Feizabadi ae51f9aee9 fix(import): share repeated KML styles before resource checks 2026-10-14 04:06:19 +02:00
Mazeyar Moeini Feizabadi a5b21b5d0f fix(import): enforce geometry budgets and queued navigation 2026-10-14 01:02:50 +02:00
Cliff Flood 001043f74e fix(bikeshare): let one dead city feed fail without failing the layer
The layer recorded failure in a single `_error` string. Every city feed is
fetched independently, so one retired operator set that flag for the whole
layer — and the only code that cleared it ran on a successful *activation*,
which `runProximityCheck` skips for a city that already has rendered points.
A dead feed that re-entered camera range therefore set the flag on every
camera move and nothing ever cleared it: a permanent LOAD FAILED over a map
drawing every other city's stations.

Failure is now tracked per city in `_failedCityIds`, and `getStats()` reports
it only when the failures left nothing to draw. A city that recovers removes
its own entry rather than waiting for a neighbour to succeed.

This was reachable only because Buffalo sits 95 km from Toronto, inside the
100 km activation radius — the one dead city in the registry with a healthy
neighbour in range. The other four failed alone, where LOAD FAILED with an
empty map reads as correct, which is why the latch went unnoticed.

Probing all 33 registry systems found five dead. Three had moved and are
repointed: Reddy Bikeshare (Buffalo) to Social Bicycles, Tugo (Tucson) and
Trinity Metro (Fort Worth) to PBSC, all verified serving stations. Two are
dropped because the systems wound down rather than moved — Broward B-cycle
404s at every documented endpoint, and CoGo's replacement Lyft feed publishes
zero stations with status last reported in March 2025. `gbfs.cogobikeshare.com`
no longer resolves, so its allowlist entry goes too.

All 31 remaining systems were verified live, and every registry URL was
checked against the proxy host and path allowlists.
2026-10-13 18:55:20 -04:00
Cliff Flood b8ccfd1648 feat(bikeshare): add Bike Share Toronto
Toronto runs the same PBSC platform as the Austin, Honolulu and
Chattanooga systems already in the registry, and publishes the identical
GBFS v2 endpoint pair under `toronto.publicbikesystem.net`. The proxy
allowlist already admits the host through its `*.publicbikesystem.net`
wildcard and the paths end in the expected `station_information.json` /
`station_status.json`, so the system needs no new plumbing — only the
registry entry that names it.

Verified against the live feeds: 1,069 stations in both documents, all
1,069 joining on `station_id`. The layer reads `num_bikes_available`,
which Toronto populates normally, so availability renders without a
vendor-specific mapping. It does not populate the standard
`num_bikes_available_types`, reporting per-type counts under PBSC ids
(ICONIC/BOOST/EFIT/ASTRO) instead; nothing reads that field today, and
this entry deliberately does not translate it rather than adding a
mapping with no consumer.

The center is downtown at 43.6532, -79.3832 with the group's 90 km load
radius. The stations span roughly 37 km east-west, from Etobicoke to
Scarborough, so a tighter radius would drop the outer ends on a downtown
pan.

The new registry test is the reason this was cheap to be sure about: it
holds every city's feed URLs against the same host and path predicates
the proxy enforces, so a city the proxy would silently refuse now fails
the suite instead of rendering an empty layer.

Credited to Bike Share Toronto (Toronto Parking Authority). The City's
open-data package declares no licence and the feed publishes no
`license_url`, so it is treated as attribution-only, like the other GBFS
operators, rather than claiming a licence that was never granted.
2026-10-13 18:55:20 -04:00
Cliff Flood 51b89d3e4a feat(cctv): add the City of Toronto RESCU camera pack
The province's 511 pack covers Ontario's highways; this adds the municipal
network underneath it — roughly 336 cameras across downtown arterials plus
the Gardiner, DVP, Allen and Lake Shore, from the City's own open data.

The list is keyless and carries no frame URL, so frame URLs are built from
the convention the dataset documents (`CameraImages/loc####.jpg`) and a
camera number validated as plain digits. The frame proxy is therefore
pinned to the portal origin by construction rather than by trusting a
field. The list fetch refuses redirects, bounds the body it buffers, and
releases the transport on every rejection path.

The dataset publishes no camera facing. `D1`-`D4` look like a compass and
map trivially onto one, but they describe the *comparison* images — static
reference stills captured in 2016 and served from a different path — not
the live pan-tilt-zoom frame. A heading derived from them would be
confidently wrong for every camera in the city, so every camera takes the
shared id-hash fallback at low confidence, as headingless Austin, TfL,
Fintraffic and Calgary cameras do. A test pins that down so it is not
"fixed" later.

Names stay verbatim: the feed's labels are upper-case, and title-casing
would mangle MCCOWAN RD and ST HELEN'S AVE more often than it helped.

Carries the Open Government Licence – Toronto attribution the licence
requires. Disable with `CCTV_TORONTO_ENABLED=0`.
2026-10-13 18:54:59 -04:00
Mazeyar Moeini Feizabadi 7694c02b91 Integrate file-import contribution onto current main for HAL-526 review 2026-10-14 00:50:18 +02:00
Mazeyar Moeini Feizabadi c349a89bb2 fix: keep fallback emergency status paired with admitted aircraft 2026-10-13 18:11:41 +02:00
Mazeyar Moeini Feizabadi ec80c89c1e fix: integrate GNSS and emergency features with current main contracts 2026-10-13 17:42:30 +02:00
Mazeyar Moeini Feizabadi 69e8b18e02 Merge rebased aircraft emergency contribution for HAL-522 validation
# Conflicts:
#	DATA_SOURCES.md
2026-10-13 17:25:47 +02:00
Leo PechnickiandClaude Opus 5.5 7d6f31e54d feat(squawk): carry emergencySource + observation time into analyst records
Review on #856 (kvnloo): the analyst projection flattened a 7700 squawk and
the readsb ADS-B emergency field into the same emergency/emergencyKind pair.

- mapAnalystRecord (flights, military) adds emergencySource ('squawk' |
  'ads-b' | null, from aircraftEmergency().source), emergencyBroadcast (new
  pure emergencyBroadcastPhrase: "broadcasting squawk 7700 (general
  emergency)" vs "ADS-B reports general emergency") and observedAtMs (the
  record's lastContactEpochMs: last transponder message, epoch ms).
- emergencySource is a queryable analyst text field; the voice payload passes
  it and emergencyBroadcast through, and observedAtMs only for aircraft with
  a status. Tool description asks the model to narrate with the phrase.
- Source-to-analyst fixture test: OpenSky 7700 vs adsb.lol emergency=general
  on squawk 1200 differ in provenance and timestamp; filterable by source.
- Voice tool-payload pins re-derived for the additive description change.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-13 17:23:39 +02:00
Leo PechnickiandClaude 15b13e947b fix(flights): address review — quotable squawk only, all military tint sites, no test churn
- aircraftEmergency: `source` is 'squawk' only when the Mode A code itself
  names the status; the Cockpit HUD no longer quotes an unrelated squawk
  (e.g. SQUAWK 1200 on an ADS-B `downed` status).
- military: new billboards and the untrack restore use the fleet tint, so an
  emergency stays red instead of snapping back to amber; tint helpers take the
  record already in hand instead of a second lookup.
- cockpit/cyber CSS: emergency colour via a custom property / theme token,
  meta line bolded so the status does not rely on colour alone in the HUD.
- tests: revert Prettier churn in unscoped test files; only semantic edits.
- docs/CURRENT-STATE.md: transponder emergency highlighting section.
- qa-emergency-squawk: (iv) RELEASE check; new files added to format scope.

Co-Authored-By: Claude <[email protected]>
2026-10-13 17:23:19 +02:00
Leo PechnickiandClaude eb7f059750 feat(layers): highlight aircraft broadcasting a transponder emergency
Flights and Military Flights tint aircraft red while the latest poll
carries squawk 7500/7600/7700 or an adsb.lol ADS-B emergency status
(general/unlawful/nordo/downed). Minimum-fuel and lifeguard priorities
are reported but not tinted. The Cockpit HUD aircraft-meta line names
the broadcast code in red. The status is not sticky: a cleared code
stops highlighting on the next refresh.

The analyst/voice query engine gains squawk, emergency and
emergencyKind fields. No new source or request: OpenSky state vectors
already carry the squawk and adsb.lol/readsb carries both fields.

Built by the Hex project (Crew Leo Agile dev team).

Co-Authored-By: Claude <[email protected]>
2026-10-13 17:22:29 +02:00
Leo PechnickiandClaude Opus 5.5 783c5b16f4 fix(gnss): date replayed snapshots by the proxy-reported age, not cross-clock fetchedAt
The layer compared the server's fetchedAt with the browser's clock, so a
skewed client clock could shift or void the 30-minute window. The proxy now
returns ageMs (its own now minus fetchedAt, at serve time, on fresh, cached
and stale answers); the source refuses a snapshot without a finite,
non-negative ageMs, and the layer dates rows as its now() - ageMs. fetchedAt
stays in the payload for display.

Tests: proxy cached/stale answers report ageMs on the server clock; the
source rejects missing/invalid/negative ageMs; the layer replay test drives
ageMs. qa-gnss stubs send ageMs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 17:20:43 +02:00
Leo Pechnicki fde8b2a64f fix(gnss): age degraded evidence and replayed snapshots on their own clocks
Maintainer review on #855 (mazy1998, 2026-10-06):

- records: presence (seenAt) and degraded evidence (degradedAt) age
  separately, so continuing healthy reports no longer keep an older
  degraded flag alive past 30 minutes; an aircraft returning after the
  window starts fresh. pruneGnssObservations ages the store with no new
  rows.
- Rows are dated by the snapshot's fetchedAt, which the proxy keeps on
  cached and stale answers: a replay never restarts the window, the
  proxy stops serving a stale snapshot older than the window, the source
  refuses an undated one, and cells expire during fetch failures and
  while there is no view anchor.
- Normalization accepts ADS-B versions 1 and 2 only; a missing, invalid
  or negative seen_pos is not a confirmed position from the last minute.
- qa-gnss: keyboard, 390x844 viewport (fresh page: isMobile reloads) and
  replay-age sections; the live cell assertion bins the returned rows
  with the layer's own rules instead of a raw row count.
2026-10-13 17:20:43 +02:00
Leo PechnickiandClaude Opus 5.5 6d4a2a02fe fix(gnss): separate GEV integrity classifier from GPSJAM aggregation; machine-readable provenance
Review on #855: the per-aircraft rule (NIC < 7 || NACp < 8, borrowed from
the US 14 CFR 91.227 ADS-B Out minima) is GEV-defined, not gpsjam's, and
gpsjam's map shows low navigation accuracy, not necessarily jamming.

- Primary cell state is now `navigation-integrity-anomaly` (medium/high) or
  `nominal`; `suspected-gnss-interference` is a secondary `interpretation`
  marked validated: false.
- GNSS_PROVENANCE / gnssProvenance({ windowMs }) records the classifier
  (gev-nic-nacp-v1, GEV, unvalidated), the gpsjam aggregation (formula,
  bands [0.02, 0.1], FAQ source) and the GEV 30-minute visited-view window,
  built from the constants the code applies. Exposed as layer.provenance
  and getStats().provenance; the proxy tags responses with `classifier`.
- Visible name "GNSS Integrity", legend "... low accuracy", blurb leads with
  low navigation accuracy and states the threshold is a GEV choice.
- Layer id `gnss-interference` and share token `0` unchanged.
- Voice aliases add "gnss integrity", "navigation integrity",
  "low navigation accuracy"; the interference aliases stay.
- Docs describe the method as GEV threshold + gpsjam aggregation.
- Tests: provenance object, renamed state/label, proxy classifier tag;
  qa-gnss asserts provenance and wording in the real app.

Hex project - Crew Leo Agile dev team.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-13 17:20:43 +02:00
Leo PechnickiandClaude 21201c78f0 fix(gnss): address review - reference source wiring, honest method, 429 backoff, QA render proof
- Route the adsb.lol GNSS source through createReferenceSources and the
  constructCatalog contract; app layer module is a thin pass-through.
- Describe the method honestly: gpsjam.org's published cell formula and
  bands; per-aircraft thresholds are the 14 CFR 91.227(c) ADS-B Out minima
  (NIC < 7, NACp < 8) plus readsb gpsOkBefore.
- Proxy: reuse the adsb.lol anchor parser, honour upstream Retry-After
  (clamped 5-120 s), serve stale during cooldown, cap the body size.
- Layer: redraw only when a cell id or band changes, treat a settling
  camera as a retry rather than a rejected enable, keep low cells visible,
  skip rows without finite coordinates, state the 3-aircraft rule in the
  legend blurb.
- Voice: gnss-interference in set_layer_visibility / show_data_layers_menu
  plus common aliases; voice pins re-derived.
- qa-gnss: stub the route in-page (request interception stalls Cesium's
  geometry workers), assert every cell is built, cover all bands over land
  and sea, screenshot every state with the Data Layers row open.

Hex project - Crew Leo Agile dev team.

Co-Authored-By: Claude <[email protected]>
2026-10-13 17:20:03 +02:00
Leo PechnickiandClaude eefcb338b3 feat(layers): GNSS interference layer from ADS-B NIC/NACp integrity
Bins airborne ADS-B v1/v2 aircraft that report degraded navigation
integrity (NIC < 7, NACp < 8, or readsb's GPS-loss flag) into 0.5 degree
cells over a rolling 30-minute window, coloured with the gpsjam.org
bands. Keyless: reads the capped adsb.lol point snapshot around the view
through /api/gnss-integrity, which returns integrity fields only, caches
60 s per whole-degree anchor, backs off on upstream 429 and serves the
last snapshot on failure. Adds scripts/qa-gnss.mjs.

Built by the Hex project (Crew Leo Agile dev team).

Co-Authored-By: Claude <[email protected]>
2026-10-13 17:19:23 +02:00
Said TurkseverandClaude Opus 5.5 b1efd22f02 feat(street-level): one imagery source at a time; IC8 review fixes
- One provider is lit at a time: lighting a chip darkens the others, and a
  chip click records every registered provider's switch in one update so
  the share link keeps the swap (also off Google 3D, where Street View is
  not listed). The layer starts with the first default-on provider
  (Mapillary, free); params that light several keep the one already on,
  so reapplying them never flips (litByParams). The now-unreachable
  "several lit" chip paths are gone.
- Leaving Google 3D during a Street View lookup ends it without an error
  or a stuck loading state (openImage's early return resets it; the
  lookup loop rechecks availability).
- A source swap during a lookup no longer reports "no imagery".
- Street View lit off Google 3D says the panel needs the Google 3D map.
- Comments trimmed to the why; keySetupCore.test.mjs back to upstream's
  formatting plus the one new test (was a 551-line reformat).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 15:10:58 +01:00
Aditya fc48eda113 fix(radio): reject null-body and out-of-range mirror statuses instead of crashing
fetchPinnedRadioResponse built `new Response(stream, { status })` inside
the raw https response callback, which runs outside the surrounding
promise. A Radio Browser mirror answering 204, 205 or 304 (null-body
statuses), or any status outside 200-599, made the Response constructor
throw. Nothing caught it, so the whole dev/preview server process exited
and every layer went down, not only radio. The catalog's mirror failover
never saw the error.

Mirror the guard local-receivers.js already uses: null-body statuses get
a null body, statuses outside 200-599 are rejected, and anything thrown
in the callback rejects the promise so the existing error handling and
mirror failover run.
2026-10-13 17:04:20 +05:30
Matt Van Horn 3cf9a8d65d feat(cctv): add NYC DOT Traffic Management Center camera pack
Register the keyless webcams.nyctmc.org catalog as a live CCTV source,
synthesize frame URLs from validated camera UUIDs, and keep the nearest
cameras to the five borough cores under the existing catalog ceiling.
2026-10-12 19:18:45 +00:00
Said TurkseverandClaude Opus 5.5 76db4114ff Merge upstream/main into pr/google-street-view
Conflicts with upstream's Street Level provider composition and share-state
codec, resolved:

- Street View's switch moves from its own share option (`g`) to upstream's
  provider-switch field (`r`, e.g. `0.r.google-1`); a link without it keeps
  Street View off. Docs and the browser gate follow.
- createApplicationStreetLevel keeps upstream's injectable provider list;
  its default, once the application supplies its Street Level source, is
  Mapillary plus Google Street View. Without that source there are none, as
  upstream intends.
- The coverage hint keeps upstream's empty-composition message and joins
  every switched-on provider's hint otherwise.
- CHANGELOG, README and SECURITY keep both sides' entries.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-12 11:32:05 +01:00
ulihhhh fef7878e54 Merge remote-tracking branch 'upstream/main' into feature/catalonia-cctv-cameras 2026-10-12 12:29:16 +02:00
kapturnerandClaude Opus 5.5 90b783c532 fix(import): one blob URL per packed KMZ image, cap KML styles and links
A KMZ could name one large packed image in thousands of <href>s, and each
one made a fresh Blob copy for Cesium to decode. kmzImageResolver now keeps
one blob URL per archive entry, and countKmlGeometry refuses a document
with more than 2,000 <href> and <Style> elements (MAX_KML_LINKS) before
Cesium reads it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 21:55:11 -05:00
kapturner d8b4b0d80f Merge branch 'main' into feat/import-geo-files 2026-10-11 21:18:37 -05:00
trygvehhh 242473a1ea Merge branch 'main' into feat/bikeshare-norway 2026-10-11 13:24:19 +02:00
Sameh Khamis eacfc1b06a Persist explicit provider toggles through the layer state coordinator 2026-10-09 19:09:30 -07:00
Sameh Khamis 3ba8c6d61b Use a neutral compact switch codec and clarify provider size limits 2026-10-09 18:47:04 -07:00
Sameh Khamis fbe118aab9 Merge branch 'refactor/route-imagery-sources' into fix/street-level-provider-sharing 2026-10-09 18:44:12 -07:00
Sameh Khamis 8d7c47ec39 Merge branch 'feat/optional-catalog-sources' into refactor/route-imagery-sources
# Conflicts:
#	CHANGELOG.md
2026-10-09 18:44:07 -07:00
Sameh Khamis 161a3a796a Keep source availability in the catalog and cover absent military acquisition 2026-10-09 18:43:44 -07:00
Sameh Khamis 7b1b2df764 Preserve custom Street Level provider switches in shared state 2026-10-09 17:53:47 -07:00
Sameh Khamis 99988cb348 Separate route and recent imagery acquisition from application assembly 2026-10-09 17:42:00 -07:00
Sameh Khamis 5756ae92a8 Make catalog feed configuration optional and explicit 2026-10-09 17:35:38 -07:00