Notes on how the upstream ArcGIS service actually behaves, why ArcGISClient
queries each layer twice, and which gaps are outside the client's control.
Measured 2026-08-11 over a 90 minute window, 180 samples at 30 second
intervals, comparing ArcGISClient, FeedClient and WebClient side by side.
18 distinct incidents passed through, covering all three layers.
https://utility.arcgis.com/usrsvcs/servers/a1f6aa7faab44b1582029509c46dce86
/rest/services/Maps/Public_LiveFeeds/MapServer
Three point layers, maxRecordCount 2000, no definition expression, no time
info:
| Layer | Name | Category |
|---|---|---|
| 0 | Fire Incidents | FIRE |
| 1 | EMS Incidents | MEDICAL |
| 2 | Traffic Incidents | TRAFFIC |
This is the same service the official LCWC live map consumes. The map at
lcwc911.us/live-incident-map embeds web app cc2eb34d14ce4f2ba15e1f1a3ccb6a01,
whose web map 5b0e126547b046e69e9559ea866bdf34 lists exactly this MapServer as
its Live Incidents operational layer with a 30 second refresh. There is no
richer or alternate endpoint to fall back on, which is why gaps in this service
show up identically on the official map.
This is the root cause of #3.
The service routinely holds rows whose geometry is null, because the address has not been geocoded yet or never will be. Any query that asks for geometry drops those rows without comment, and a spatial filter implies one. Same layer, same instant, only the output flags varying:
geom=false=4 geom=true=2 geom=true,outSR=4326=2 countOnly=4
returnCountOnly and returnGeometry=false agree on 4. Asking for geometry
returns 2. Identifying the rows that vanish:
OK oid=4 2608012247 WEST LAMPETER TOWNSHIP geom={'x': -8490111.67, 'y': 4863072.28}
OK oid=5 2608012253 CLAY TOWNSHIP geom={'x': -8487468.24, 'y': 4897429.80}
DROP oid=6 2608012253 CLAY TOWNSHIP
DROP oid=7 2608012270 MANHEIM BOROUGH | E HIGH ST / S HAZEL ST
The dropped rows carry no geometry at all: returnExtentOnly=true on either one
returns {"xmin": "NaN", "ymin": "NaN", "xmax": "NaN", "ymax": "NaN"}. They are
unreachable through every output variant tried, including f=geojson,
returnCentroid=true, outSR=102100, geometryPrecision and quantization.
Normally a null-geometry feature comes back as "geometry": null; this service
omits the row entirely.
Manheim Borough above had no geocoded twin, so that incident was invisible to any geometry-bearing query.
The spatial envelope was never the problem. returnGeometry=true with no
spatial filter whatsoever still returns the reduced set, so widening the
envelope, splitting the county into quadrants, or dropping the filter changes
nothing. The envelope has been removed because where=1=1 alone already returns
every row the service holds, and the filter could only ever subtract.
Geometry also flaps. Clay Township had coordinates at 23:51 and none at 23:55, so a row that answers a geometry query now may not answer the next one.
Each layer is queried twice: once with returnGeometry=false for the
authoritative row set, once with returnGeometry=true purely as a coordinate
lookup keyed on IncidentNumber. Incidents come from the first query, so nothing
is lost; coordinates are attached when the second query has them.
ArcGISIncident.coordinates is therefore Optional[Coordinates]. Over the
measurement window the client returned coordinates for 741 of 775 incidents
(96%).
The service sometimes carries more than one row for a single incident, typically
one geocoded and one not (oid=5 and oid=6 above are both incident
2608012253, identical in every attribute). The client dedupes on
IncidentNumber per layer.
Duplicate and null-geometry rows appeared in 26 of 180 samples, clustered in bursts rather than spread evenly. Across the window a geometry-bearing query would have dropped 4.7% of rows on average, and 50% in the worst sample.
Four incidents in the window never appeared in the service at any point in their lifetimes, across every sample the feed carried them:
[NEVER] 150/150 EAST LAMPETER|LANDIS AVE + LINCOLN HWY E ROUTINE TRANSFER-CLASS 3
[NEVER] 99/99 ELIZABETH|HOPELAND RD + LEE LN ROUTINE TRANSFER-CLASS 3
[NEVER] 40/40 QUARRYVILLE|PARK AVE + S HESS ST EMS ACTIVITY
[NEVER] 30/30 FULTON|ROBERT FULTON HWY + WARFEL RD ROUTINE TRANSFER-CLASS 3
Only two types, ROUTINE TRANSFER-CLASS 3 and EMS ACTIVITY. Every
emergency-type incident reached the service, including fire and traffic. This
looks like a deliberate upstream filter on the public map rather than a defect,
and no client-side change can recover them. Callers who need complete coverage
of non-emergency EMS activity should use FeedClient or WebClient.
Aggregated over the 14 incidents that did reach the service, 790 samples of lifetime:
| Behavior | Measurement |
|---|---|
| Ingest lag before the service picks an incident up | ~19s |
| Trailing presence after the feed clears it | ~13s |
| Mid-lifetime single-sample dropouts | 6 (0.76% of samples) |
The dropouts are the notable one. An incident the service is already carrying can
vanish for a single poll and return on the next, presumably during the same table
rebuild that produces the empty-layer blips below. Rendering two incident
lifetimes at 30s per character, F = feed only, B = both, A = ArcGIS only:
LANCASTER|CHESTER ST + S DUKE ST FBFBBBBBBBBBBB...BBBBFBBBBBB...BBBBA
EAST PETERSBURG|SUNDRA CIR FBBBBBBBBBBBBB...BBBBFBBBBBB...BBBBB
A consumer diffing consecutive polls will see spurious clear/re-open pairs at roughly 1 sample in 130. Debouncing by one poll suppresses it. The client does not do this, because a genuine clear-down is indistinguishable from a dropout within a single sample and the delay would be paid on every incident.
Separately, the whole layer occasionally returns zero rows mid-refresh: 2 of 151 samples in an earlier 6 minute run at 2 second intervals, 0 of 180 in the 90 minute run. A poller can misread that as "all incidents cleared". A retry on empty would mask it, but zero is also legitimate during quiet hours, so the client does not retry.
Found while cross-checking the three clients, not an ArcGIS issue.
MEDICAL_UNIT_NAMES in src/lcwc/feed/utils/__init__.py is
["AMB", "EMS", "INT", "MEDIC", "QRS"]. MICU is missing, and that one omission
causes two failures, because the list gates both has_unit_names() in
feed/parser.py and determine_category():
- The units segment is not recognized as units, so
unit_namesstays empty and the MICU unit is discarded entirely. - With no units, classification falls through to the description keyword check,
which only matches
MEDICAL.EMS ACTIVITYandROUTINE TRANSFER-CLASS 3therefore land inUNKNOWN.
Same instant, same incidents:
FEED: UNKNOWN QUARRYVILLE BOROUGH units=[] EMS ACTIVITY
MEDICAL CLAY TOWNSHIP units=[] MEDICAL EMERGENCY
UNKNOWN FULTON TOWNSHIP units=[] ROUTINE TRANSFER-CLASS 3
WEB: MEDICAL Quarryville Borough units=['MICU'] EMS ACTIVITY
MEDICAL Clay Township units=['MICU'] MEDICAL EMERGENCY
MEDICAL Fulton Township units=['MICU'] ROUTINE TRANSFER-CLASS 3
Clay Township got MEDICAL only because its description happened to say so,
which masks the unit loss. The raw feed confirms the units are present upstream:
QUARRYVILLE BOROUGH; PARK AVE & S HESS ST; MICU 56-5;.
WebClient is immune because it reads the category from the page's section
header instead of inferring it. UnitParser handles MICU fine, so the keyword
list is the only gate. This was observed across 169 samples and is not fixed.
FeedClient and WebClient returned identical incident sets in 180 of 180
samples. The only differences between them are the categories above.
Incidents are matched across sources by normalized location, since the three
sources share no identifier: the feed has a guid, the web page has nothing, and
ArcGIS has IncidentNumber. Two genuinely distinct co-located incidents (a
structure fire and its EMS dispatch, filed as separate CAD incidents at one
address) therefore collapse into a single key. This happened in about 10 of 180
samples and is a limitation of any cross-source comparison, not of the clients.
The quickest way to observe the core defect directly:
GET .../MapServer/1/query?f=json&where=1=1&returnCountOnly=true
GET .../MapServer/1/query?f=json&where=1=1&outFields=IncidentNumber&returnGeometry=false
GET .../MapServer/1/query?f=json&where=1=1&outFields=IncidentNumber&returnGeometry=true
Whenever the third disagrees with the first two, the difference is rows the service holds but will not hand over with geometry attached.