Commit Graph
73 Commits
Author SHA1 Message Date
Sameh Khamis 24f14a77a3 Merge branch 'main' into feat/wsdot-camera-pack
Keeps main's 4,000 catalog-wide camera cap, which main pins in tests; WSDOT
shares it round-robin with the other packs. The branch's earlier cap raise and
its removal of main's cap tests are reverted in this merge.
2026-10-15 14:22:22 -07:00
Sameh Khamis ac13acfe3d Merge branch 'main' into feat/aqhi
# Conflicts:
#	CHANGELOG.md
2026-10-15 13:47:21 -07:00
Sameh Khamis 51e32a30f2 fix(bikeshare): scope city failures to range and report partial outages
A failure now ends when its city leaves range or the camera rises above the
activation gate, so an empty map no longer reads LOAD FAILED. Late activation
and status rejections are ignored like late successes. Partial failure reads
DEGRADED, every in-range city failing over cached points reads STALE, and
freshness advances only on a refresh that succeeded. Behavioural tests drive
the real proximity, update and enable paths. Docs say no licence is published
for Toronto and list Social Bicycles and PBSC. The merge also restored the #61
GBFS v3 changelog entry that an earlier merge on main dropped.
2026-10-15 13:08:45 -07:00
Sameh Khamis 046126eb36 Merge branch 'main' into feat/aqhi
Port to current main: main reserved layer-state token 0 for street-level, so
air-quality takes the next free token, 4 (registry, ledger, and the allocation
tests shift by one). Main moved source contracts into sourceComposition.js, so
air-quality registers its getSnapshot contract there. Package boundaries keep
main's lists plus this branch's air-quality modules and packages.
2026-10-15 12:39:00 -07:00
Sameh Khamis c9f43e8517 Merge branch 'main' into feat/bikeshare-toronto-and-failure-fix
# Conflicts:
#	CHANGELOG.md
#	DATA_SOURCES.md
#	docs/CURRENT-STATE.md
2026-10-15 12:35:18 -07:00
Said Turksever ab14f48360 Merge branch 'main' into pr/panoramax 2026-10-15 20:17:28 +01:00
Said Turksever 42d3c0c0d2 Merge branch 'main' into feat/bikeshare-norway 2026-10-15 17:32:25 +01:00
Said TurkseverandClaude Opus 5.5 de83e1c17f Merge upstream/main into pr/panoramax
CHANGELOG: keep both new [Unreleased] entries (Panoramax, and the
emergency-transponder highlight from #856).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 12:57:53 +01: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
Said TurkseverandClaude Opus 5.5 da0d370fa3 Merge upstream/main (KartaView #1121 merged) into pr/panoramax
KartaView's later viewer changes are carried into the shared
photoViewer.js: the camera bearing (`bearingOf`), redrawing the same
photo after a GPU reset through `onReopen`, no pose while a lost context
recovers, the 2,560 px flat version only once the viewer outgrows
1,280 px, `refreshPose`, and one sharper-panorama load at a time with a
second look once it lands. Its tile cache's `keyOf` and `clear` move to
the shared tileCache.js. KartaView gets `onEscape` beside `onReopen`.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 15:52:21 +01:00
Said Turksever 02a2efb8d4 Merge branch 'main' into pr/kartaview 2026-10-14 15:13:16 +01:00
Said TurkseverandClaude Opus 5.5 b42ab9bb02 feat(street-level): IMAGERY and SINCE filters for KartaView
KartaView filters coverage on its server only in its PNG tiles (its JSON
tiles come back empty with a filter), so a filtered tile's PNG is a mask
over the cached JSON segments: a segment stays when at least half the
points along it lie on drawn pixels. A filter change reloads the lines
(lineCoverage.reload keeps the drawn ones until the new ones are in);
masks are cached per filter and tile, and a filtered tile KartaView is
still drawing (504 or a timeout) is asked again, four tries in all.
The nearest lookup asks the photo API for the projection and date, and
the cones follow the filter like Mapillary's. The gate fixture draws
filtered PNG tiles and adds an older flat-only street; a new gate step
checks 360 and LAST YEAR thin KartaView's lines and ALL brings them back.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 15:02:14 +01:00
Said TurkseverandClaude Opus 5.5 00d2b73b6a feat(street-level): Panoramax as a fourth, keyless imagery provider
Panoramax, the open federated street-level commons, registers beside
Mapillary, Google Street View and KartaView. Its meta-catalogue
(api.panoramax.xyz) is keyless and CORS-open, so it runs in the browser:

- coverage from its vector tiles: sequence lines at z11–14 below 30 km
  (longest first under the per-tile cap), and above that the grid layer's
  density cells as binned points, not counted as sequences;
- a click on a line opens that sequence's picture nearest the click
  (STAC search, any direction), without moving the camera, then any
  sequence's if it has none within 50 m; the 360° and since filters go to
  the lines and to the API;
- cones from the z15 tiles' pictures layer around the open picture
  (~110 bytes a picture, against ~7.5 kB for a STAC item), re-centred when
  a picture opens outside them; ‹ › follow the picture's prev/next links;
- the caption names the author (not an account named by an email
  address) and the picture's licence (StreetPose `license`), and links to
  the picture in the Panoramax viewer; the globe credits Panoramax.

KartaView's viewer becomes the shared photoViewer.js (flat <img>, 360° on
panorama.js, ‹ ›, keyboard, pinch, context loss), driven by a per-provider
PhotoSources table; the request limiter moves to limiter.js. Panoramax shows
the 2,048 px SD derivative and fetches the HD original only when the viewer
is wide enough, once, shrunk while it decodes (never above 8,192 px).

Orange #ff6f00 (Panoramax's own), off by default, share option
0.m.0_0.r.panoramax-1. The MCP panel allows the meta-catalogue and the
biggest instances. Tests: policy, decode, source, viewer, provider, and a
Panoramax fixture in the hermetic browser gate.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 13:10:40 +01:00
Said Turksever 40be3bc54d Merge branch 'main' into fix/nyc-cctv-pack 2026-10-14 12:52:49 +01: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
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
Mazeyar Moeini Feizabadi a922d71120 test: isolate GNSS first-fetch recovery from persisted fixtures 2026-10-13 21:51:41 +02:00
Mazeyar Moeini Feizabadi 96534df807 fix: refresh GNSS sampling automatically as the camera moves 2026-10-13 21:17:10 +02:00
Said TurkseverandClaude Opus 5.5 310984ff0b test(street-level): KartaView in the hermetic browser gate; docs
The fixture gate answers api.kartaview.org, cdn.kartaview.org and
*.openstreetcam.org from fixtures (a drive with a 360° photo, stored on
storage2 while the API names storage1) and adds three steps: keyless
coverage with its credit and hidden filters, a line click opening the
nearest photo with cones and ›, and a 360° photo on the panorama without
FIT / FILL. The Street View share-link check reads the switch field instead
of one exact entry, since a chip click records every provider's switch.

README, DATA_SOURCES, CHANGELOG and CURRENT-STATE describe KartaView.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 18:42:36 +01: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 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 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
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
bassem chagra b7d25f4c69 Merge origin/main into feat/wsdot-camera-pack
Resolve the source-pack conflicts with Statens vegvesen (keep both packs).
The Norway pack's 900 default pushed the per-pack defaults to 5,204, past
the 4,500 catalog cap this PR enforces, so raise DEFAULT_CCTV_MAX_SOURCES
to 5,500 and CCTV_MAX_SOURCES_CEILING to 6,000.
2026-10-08 15:59:09 +02:00
Said TurkseverandClaude Opus 5.5 7bfcf177ac fix(street-level): IC8 review of the Street View provider
Google's Maps Platform terms forbid Street View imagery beside non-Google
maps, so the provider declares requiresMapStack: 'photoreal': off Google
3D its chip is dashed with the reason, lookups and opens skip it, and
leaving Google 3D closes its panorama.

- Ground clicks: only a click on the map itself (scenePick.isSurfacePick:
  nothing picked or Google 3D tile content) at street zoom opens Street
  View, and the camera stays put; higher up the hint says to zoom in.
  scenePick.pickGroundPosition replaces the copy in Directions.
- Viewer: poses go out at once and again when the date and address
  arrive, so an open never hangs on that lookup; one lookup per panorama,
  seeded by the nearest lookup; a close settles a pending open; failed
  lookups are asked again; poses follow position changes, not pano_changed.
- Loader: the gm_authFailure handler is installed once, so a retried load
  reports a refusal once.
- Viewer host: a prewarm that lands after another provider took the host
  is released; FIT/FILL availability is set on every open.
- Provider: a refusal while switched off reports no error over another
  photo; SINCE compares against the end of Google's month; messages name
  the referrer and network causes; FLAT says Street View is 360° only.
- The layer row names the key of the providers that are on; the MCP panel
  CSP admits Street View's tiles, control images and photos.
- Tests for each, against fakes that now follow Google's event order; the
  browser gate restores its state, waits instead of sleeping, aims its
  panel clicks and corner drags, and asserts the camera stays put.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 02:59:51 +01:00
Said TurkseverandClaude Opus 5.5 22b0009138 feat(street-level): Google Street View as the second imagery provider
Google Street View registers beside Mapillary as provider `google`. It runs
on the Maps JavaScript API with the browser GOOGLE_MAPS_API_KEY, loaded on
first use (mapsLoader.js), and uses Google's own StreetViewPanorama as its
viewer adapter, emitting provider-neutral poses (address and month in the
caption, a link to Google Maps, steps along Google's arrows, FOLLOW on
Google 3D). Its chip starts off because every panorama is billed to the
key; the share option is `g`.

Google offers no coverage layer for other maps, so the provider draws
none: with it on, a click on bare ground at street zoom opens its nearest
Google-collected outdoor panorama (groundClick.js). A key Google refuses
reads KEY REJECTED and fails a pending open at once; a lookup Google never
answers fails after 10 s.

Core: providers may declare `groundClick` and `defaultOn`; poses may carry
`capturedAtPrecision` and `title`; the coverage line keeps every
provider's hint; opening one provider's image releases another's
prewarmed viewer; FIT/FILL hides for viewers without render modes. CSP
script-src admits https://maps.googleapis.com. The browser gate gains two
Street View steps (the keyed one skips as 'no Google key' in CI).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 02:32:06 +01:00
Trygve Hemminghytt 8152a48a66 Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	CHANGELOG.md
2026-10-07 15:44:20 +02:00
Said TurkseverandClaude Opus 5.5 4ea6631425 docs(street-level): shorten docs and comments before merge
Trim the doc text this PR adds (README, CHANGELOG, CURRENT-STATE,
KNOWN-ISSUES, SECURITY, DATA_SOURCES, .env.example, the CI job comment),
drop code comments that restate the code, cut design-note JSDoc to a line
or two, and drop review tags from test names. Comments only; no code
changes.

Also: README key count (seven keys, two metered), CURRENT-STATE's gate
paragraph (CI runs a production build with a dummy token), the stacked
doc above meshBoxInRange and the orphaned inMeshRange line in
coverage.js, and a duplicate ALPR row in DATA_SOURCES that a merge had
brought back.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 21:59:12 +01:00
Trygve HemminghyttandClaude Opus 5.5 fa61955cf1 feat(bikeshare): add Kolumbus, Farte and Lillestrøm city bikes
Cover every Norwegian station-based city-bike system with an open GBFS
feed: Kolumbus Bysykkel (Stavanger) and Farte Bysykkel (Skien/Porsgrunn)
through Entur Mobility, and Bysykkel Lillestrøm through JCDecaux
Cyclocity.

api.entur.io and api.cyclocity.fr join the GBFS allowlist, each kept to
its GBFS path prefix since both hosts front other APIs. Entur serves its
feeds without a .json suffix, so the endpoint checks accept either form,
and requests to Entur carry the ET-Client-Name header it requires.
Attributed under NLOD (Entur) and Licence Ouverte (JCDecaux).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 23:02:37 +02:00
Trygve HemminghyttandClaude Opus 5.5 42543c1fa1 feat(bikeshare): add Oslo, Bergen and Trondheim Bysykkel
Add Norway's three Urban Sharing city-bike systems to the Bike Share
layer and get_bike_share. The feeds are keyless GBFS on
gbfs.urbansharing.com, which joins the proxy allowlist. The proxy now
sends the Client-Identifier header the operators ask clients to send.
Attributed under NLOD 2.0 in DATA_SOURCES.md and the data credits.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 22:13:53 +02:00
Said Turksever bb88a8b034 Merge branch 'main' of https://github.com/bilawalsidhu/gods-eye-view into pr/mapillary-layer
# Conflicts:
#	README.md
2026-10-05 17:06:24 +01:00
Soma Froghyar 9ba1b345e6 Merge branch 'main' into fix-tomtom-link 2026-10-05 17:48:49 +02:00
Said Turksever 91d8bba4a3 Merge branch 'main' of https://github.com/bilawalsidhu/gods-eye-view into pr/mapillary-layer
# Conflicts:
#	CHANGELOG.md
#	README.md
2026-10-05 13:47:54 +01:00
Soma FroghyarandClaude Sonnet 5.5 ee7a5fb30b fix: link TomTom key setup to /keys and terms to docs.tomtom.com
Address review feedback on #903: the DATA_SOURCES terms link now points
at the actual terms page instead of a sign-in page, key-creation links
go straight to my.tomtom.com/keys, and the README table row is realigned.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-05 09:34:55 +02:00
Soma FroghyarandClaude Sonnet 5.5 491a856a6b fix: point remaining developer.tomtom.com links to my.tomtom.com
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-05 09:34:55 +02:00
H4ldenandClaude Opus 5.5 10d10eab6b fix: address review on the Statens vegvesen CCTV pack
- Lower the Vegvesen default cap to 900, still above the ~850 working
  cameras, so the per-pack defaults stay closer to the catalog default.
- Name the flat ground-elevation prior as a known limitation: the feed
  is 2D, and mountain-pass cameras can sit below terrain where neither
  the point-height prior nor the ground snap resolves.
- README: ~3,900 public cameras.
- Use one HLS figure (~135 working) in CHANGELOG and DATA_SOURCES.
- DATA_SOURCES: list the frame and HLS hosts alongside the catalog host.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 05:47:50 +02:00
H4ldenandClaude Opus 5.5 d43478a547 feat: add Statens vegvesen (Norway) road cameras as a CCTV pack
Norway's ~850 working road cameras load from one keyless GeoJSON request
to the agency's OGC API view of its DATEX 3.1 CCTV table, so no DATEX
account is needed. Faulty cameras are dropped, every camera sits under a
"Norway" category, and the ~135 that publish HLS play as live video
through the existing in-memory relay with the still as fallback. Frames
and manifests are pinned to each camera's own path on the agency hosts.

CCTV_VEGVESEN_ENABLED=0 disables the pack, CCTV_VEGVESEN_MAX_SOURCES
caps it (nearest the largest cities first) and CCTV_VEGVESEN_VIDEO=0
keeps stills only. Attributed under NLOD 2.0.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-04 22:23:16 +02:00
rileygramlich 8887ca47eb feat(air-quality): add the Air quality layer to the Weather group
Reworks #568 to the shape asked for in review.

Generalized from "AQHI" to a provider-backed Air quality layer, with ECCC's
AQHI as the first registered provider. Readings are carried as
{ provider, scale, value, band } rather than a bare number, because
air-quality indices are not interchangeable: AQHI runs 1-10+ on health risk,
the US AQI runs 0-500 on concentration breakpoints, and Europe's EAQI is a
five-step category. Naming the index a value belongs to is what lets another
network be added without inventing a shared numeric meaning. Coverage is
stated as "Canada only" on the provider, the layer row and the card.

Adds the WEATHER panel readout (readout: true) carrying the band legend and
the worst readings currently in view, with getRowControls/setRowControlsListener
following the wind and cyclone cards. An unresolvable view rectangle degrades
to the worst readings overall rather than to a blank card, and a rectangle
crossing the antimeridian is handled.

update() now takes the earthquakes layer's abort-and-guard shape: it aborts any
in-flight request, passes the signal through to the source, and refuses to
touch the scene when the request was superseded, aborted, or the layer was
disabled while it was outstanding. disable() and destroy() abort too. Tests
cover the late-response, superseded-refresh and disabled-update paths.

Rebased on main: the source is registered in src/sources/reference.js, and the
allocation profile was re-measured against the current worker — median 3,900
B/frame, max 4,114, 85.7 B/candidate, inside the shared 154 ceiling, budgeted
at 5,200 for 26% headroom. The earlier figures no longer held.

Freshness is now judged on the observation time rather than on when the last
response arrived. lastUpdate only says the feed answered; a station that keeps
returning a reading from four hours ago would otherwise be narrated as live by
the HUD and the voice provenance envelope. getStats() reports observedAt and
stale, so layerFeedState() calls the layer stale past two missed hourly
publications, and degraded when a refresh fails over readings that are still
good.

The share-link token is 0, which is what layer-token:next allocates. Taking it
moves the ledger fixtures that had hard-coded 0 as the free digit and 3 as the
one after; those shift to 3 and 4. The pinned equality between the reservation
ledger and LEGACY_LAYER_STATE_TOKENS also had to become "the closed legacy set
plus air-quality", since that set is documented as never growing. Happy to
re-pin this differently if you would rather the fixtures derive the provisional
digits from nextLayerStateToken() so the next layer does not move them again.

The layer and its source are registered as ./layers/air-quality and
./layers/air-quality/source, each with its own boundary group, following the
perimeters pair. check:boundaries requires the package exports and the group
exports to be the same set, so a layer that ships a source needs both.
2026-10-02 15:12:37 -06:00
bassem chagra 0cfb795845 Merge remote-tracking branch 'origin/main' into feat/wsdot-camera-pack
# Conflicts:
#	CHANGELOG.md
#	docs/CURRENT-STATE.md
2026-10-01 12:23:41 +02:00
Said Turksever c4514784fc Merge branch 'main' into pr/mapillary-layer 2026-09-29 15:44:25 +01:00
f4fcf267c6 fix(osm): stop using public Overpass by default (#648) (#742)
Traffic roads come from OpenFreeMap vector tiles, or TomTom flow tiles with a
key (Hybrid by default). Military areas use OpenFreeMap polygons with a bundled
worldwide name index; wide views show named points. ALPR reads an hourly
OpenStreetMap extract. Cockpit place context and country, state and US county
outlines use bundled Natural Earth and US Census data. Overpass is used only
when an operator configures their own endpoint.

Also: camera arrivals no longer land below ground, keyless terrain retries on
429, bounded relation geometry for configured Overpass, one shared
OpenStreetMap credit, and separate tile and API transports for embedders.

Co-authored-by: theGaryLarson <[email protected]>
Co-authored-by: Milan Khanal <[email protected]>
2026-09-28 19:07:57 -05:00
bassem chagra 481d0c327a fix(cctv): map WSDOT diagonal and BW compass codes; document WSDOT env
WSDOT's layer metadata defines BW (Bothways) plus the diagonals
NE/SE/SW/NW alongside N/E/S/W. Diagonal cameras were being demoted to the
low-confidence id-hash fallback; map them to 45/135/225/315 degrees and
treat BW (not B) as the no-single-facing code. Add CCTV_WSDOT_ENABLED and
CCTV_WSDOT_MAX_SOURCES to .env.example with the other pack controls.
2026-09-27 12:09:27 +00:00
Said TurkseverandClaude Fable 5.1 33ee9bf23e docs(street-level): README, DATA_SOURCES, CURRENT-STATE, SECURITY, CHANGELOG
Describe the provider-neutral layer, the PROVIDERS chip row, the shared
filter and its share-link options, and how a new provider registers.
Drop every mention of the removed plain-English query and Anthropic key.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-25 18:37:42 +01:00
Said TurkseverandClaude Fable 5.1 9ba6f96d87 Merge upstream/main into pr/mapillary-layer
Upstream took share token '2' for fire perimeters, so Street Level moves to
'3'. mapillary-js joins upstream's optimizeDeps include list instead of
overriding it; catalog and registry tests count the new upstream layers.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-25 17:58:27 +01:00
bassem chagra ee3e3c7a41 feat(cctv): WSDOT highway camera source pack (Washington State)
Adds Washington State's highway cameras as a keyless source pack, from the
Esri JSON layer WSDOT's own Travel Center map consumes
(data.wsdot.wa.gov/travelcenter/Cameras.json, ~1,700 point features).
Closes #624.

- Geometry arrives in EPSG:3857; converted to WGS84 on load and bounded to
  a Washington bounding box.
- Only frames on WSDOT's own images.wsdot.wa.gov host are registered — the
  catalog also lists ~70 partner cameras (Oregon DOT, City of Seattle,
  lodges, airports) whose own terms apply; those are skipped rather than
  proxied. 1,630 cameras survive the filters against the live feed.
- CompassDirection letters (N/E/S/W) give a high-confidence heading; the
  majority `B` ("both directions") rows carry no single facing and use the
  shared id-hash fallback at low confidence, with the usual two pose
  personalities.
- The feed body carries Windows-1252 bytes (en-dashes in titles) with no
  charset declaration, so it is decoded explicitly before parsing.
- WSDOT's layer metadata marks the feed "low volume": the 15-minute catalog
  cache and per-request frame fetches respect that, frames are never stored
  or redistributed, and the WSDOT credit is registered in the attribution
  popover. A keyed WSDOT Traveler Information API serves the same population
  for higher-volume use and is deliberately not required.
- Defaults: 250 cameras nearest Seattle and Spokane; CCTV_WSDOT_MAX_SOURCES
  changes the cap, CCTV_WSDOT_ENABLED=0 turns the pack off.
- Tests: Mercator conversion against a real layer feature, official-host and
  malformed-row filtering, compass mapping and both pose personalities,
  cp1252 decoding, env cap, upstream-failure fallback.
2026-09-25 12:32:36 +02:00
f913066cf2 feat(fires): MODIS in Active Fires and a Fire Perimeters layer (#737)
Adds MODIS NRT to Active Fires and a keyless Fire Perimeters layer (NIFC WFIGS) with
InciWeb incident links, served through a capped, cached /api/fire-perimeters proxy.

Co-authored-by: Gustavo Beneduzi <[email protected]>
Co-authored-by: James Cooke <[email protected]>
2026-09-23 21:21:52 -05:00