google / google/transit

Add activities field to informed_entity in GTFS-realtime alerts

Open
#573 4 comments 3 reactions 0 assignees View on GitHub
Discussion Period GTFS Realtime
Dominant language
No language data
Stars
1.1k
Forks
225
Avg merge
7d 17h
Merged PRs (30d)
3

Description

### Describe the problem

It is not possible to model certain common operational scenarios with the existing GTFS-RT alerts spec. When certain alerts are published, such as alerts describing rail suspensions between specific stations or alerts describing bypassed stops, the information available to consumers about what services are unavailable in a given direction at a given station is limited and can lead to misinformation and/or rider confusion.

### Use cases

## Theoretical examples

### Case 1. Service suspension in both directions between specific stations

*Service is suspended between Station 3 and Station 5. Service is available from Station 3 toward Station 1 and vice versa, and service is available from Station 5 toward Station 7 and vice versa.*

If service normally runs in both directions between Stations 1 and 7, but there is a suspension between Stations 3 and 5, the most logical available `effect` values are `NO_SERVICE` or `REDUCED_SERVICE`, where the `informed_entities` are Stations 3, 4, and 5. However, both of these `effects` leave uncertainty around what riders can or cannot do at Stations 3 and 5:

- With an `effect` of `NO_SERVICE`, it would be reasonable for consumers to interpret that there is no service available in any direction at Station 3 or at Station 5, when in fact there is service between Stations 1 and 3 and there is service between Stations 5 and 7.
- With an `effect` of `REDUCED_SERVICE`, it would be reasonable for consumers to interpret that some service is still available between Stations 3 and 5, when in fact no service is available.

### Case 2. Bypassed stops

*Stations 3, 4, and 5 are temporarily closed. Riders cannot board or exit at these stations, but passenger trains can ride through them.*

If specific stations’ entrances and exits are closed due to police activity, and riders can ride through those stations but not board or exit there, there is no way to convey this unambiguously through the existing alert spec.

- With an `effect` of `NO_SERVICE`, it would be reasonable for consumers to interpret that there is no service available at all at those stations, when in fact there is service moving through those stations.
- With an `effect` of `REDUCED_SERVICE`, it is not possible for consumers to know in what way service is reduced, i.e. riders cannot board or exit at the affected stations.

## Real-world example: Rail suspension with `effect` of `NO_SERVICE`

A suspension with an effect of `NO_SERVICE` appears in third-party applications as unavailable service between the affected stations. The limit stations of the suspension appear as having no service at all, even to and from adjacent, unaffected stations. This implies to riders that they must find another way to the limit stations from adjacent, unaffected stations, when in fact they can take normal rail service between those stations.

### Google Maps

- Suspension limits: North Station to Kenmore (MBTA in Boston, MA)
- At North Station, northbound trips (away from the suspension) are shown as cancelled and predictions are not available, despite these trips being possible and predictions being available.

Image

### Apple Maps

- Suspension limits: Back Bay to Roxbury Crossing (MBTA in Boston, MA)
- Service between Jackson Square (not part of the suspension) and Roxbury Crossing (a limit station of the suspension) is shown as unavailable, despite it being available.

Image

### Transit App

- Suspension limits: North Station to Jackson Square (MBTA in Boston, MA)
- Service between Jackson Square (a limit station of the suspension) and Stony Brook (not part of the suspension) is shown as unavailable, despite it being available.
- Service between North Station (a limit station of the suspension) and Community College (not part of the suspension) is shown as unavailable, despite it being available.

Image            Image

## Real-world example: Rail suspension with `effect` of `REDUCED_SERVICE`

A suspension with an effect of `REDUCED_SERVICE` appears in some third-party applications as seemingly normal service, with an unassuming alert that reads “Reduced service”, and details (upon tapping) that describe the limits of the suspension, specifying that service is actually unavailable.

### **Google Maps**

Image            Image

### **Apple Maps**

Image            Image

### Transit App

Image            Image            Image

## Counter-perspectives

### Only create `informed_entities` for the stations with absolutely no service

An argument could be made that in Case 1 above, only Station 4’s stops should be listed in `informed_entities`, and Station 3 and Station 5’s stops should not be in `informed_entities` at all, because Stations 3 and 5 do have some service.

We don’t believe this solution provides consumers with sufficient information to be helpful to riders. A single `informed_entity` at Station 4 could be reasonably interpreted as either a suspension of service between Station 3 and Station 5 or a simple bypass of Station 4 with full service at Stations 3 and 5. Additionally, if Stations 3 and 5’s stops are not `informed_entities`, providing stop-specific information for those stations describing what service is available would not be possible.

Perhaps more material, if service were suspended between only Station 3 and Station 4, it is unclear how that suspension could be conveyed to consumers at all using this paradigm.

Image

*Transit App: A suspension between
Park Street and Government Center,
with `informed_entities` at both, is
presented as a station bypass*

### Create multiple alerts for one service disruption

An argument could be made that in Case 1 above, there should be multiple service alerts: one with an `effect` of `NO_SERVICE` to describe the complete lack of service at Station 4, and one or two with an `effect` of `REDUCED_SERVICE` to describe the reduced service at Stations 3 and 5.

However, creating multiple alerts for one service disruption has multiple drawbacks:

- This implies that there is more than one disruption occurring when there is not. A full list of alerts along a route might include multiple alerts for a single disruption, leading to undue confusion and concern about how disrupted the route truly is.
- An `effect` of `REDUCED_SERVICE` at Stations 3 and 5 still provides no insight into what riders can and cannot do at those stations, and in what directions they can travel to or from those stations.

### Proposed solution

We propose the addition of a new `activities` field within `informed_entity` in the GTFS Realtime Alert spec. This field would have enumerated values of `BOARD`, `EXIT`, and `RIDE`, which describe the rider activities that are *unavailable* at a given `stop`.

## Case 1 solution

If we take the suspension scenario above, we can assign affected activities to each `stop` within each of the stations where service is affected by the suspension:

- Stop 3-7: `["BOARD", "RIDE"]`
- Stop 3-1: `["EXIT", "RIDE"]`
- Stop 4-7: `["BOARD", "EXIT", "RIDE"]`
- Stop 4-1: `["BOARD", "EXIT", "RIDE"]`
- Stop 5-7: `["EXIT", "RIDE"]`
- Stop 5-1: `["BOARD", "RIDE"]`

Image

*`informed_entity.activities` in red text*

Sample of a GTFS-Realtime alert with `informed_entity.activities`:

```json
{
"id": "123456",
"alert": {
"effect": "NO_SERVICE",
"effect_detail": "SUSPENSION",
"cause": "TECHNICAL_PROBLEM",
"cause_detail": "TRACK_PROBLEM",
"header_text": {
"translation": [
{
"text": "Orange Line service is suspended between Station 3 and Station 5 due to a track problem",
"language": "en"
}
]
},
"description_text": {
"translation": [
{
"text": "",
"language": "en"
}
]
},
"severity_level": "SEVERE",
"active_period": [
{
"start": 1748402460,
"end": 1748409744
}
],
"informed_entity": [
{
"agency_id": "1",
"route_type": 1,
"route_id": "Orange",
"stop_id": "3-1",
"direction_id": 0,
"activities": [
"EXIT",
"RIDE"
]
},
{
"agency_id": "1",
"route_type": 1,
"route_id": "Orange",
"stop_id": "4-1",
"direction_id": 0,
"activities": [
"BOARD",
"EXIT",
"RIDE"
]
},
{
"agency_id": "1",
"route_type": 1,
"route_id": "Orange",
"stop_id": "5-1",
"direction_id": 0,
"activities": [
"BOARD",
"RIDE"
]
},
{
"agency_id": "1",
"route_type": 1,
"route_id": "Orange",
"stop_id": "3-7",
"direction_id": 1,
"activities": [
"BOARD",
"RIDE"
]
},
{
"agency_id": "1",
"route_type": 1,
"route_id": "Orange",
"stop_id": "4-7",
"direction_id": 1,
"activities": [
"BOARD",
"EXIT",
"RIDE"
]
},
{
"agency_id": "1",
"route_type": 1,
"route_id": "Orange",
"stop_id": "5-7",
"direction_id": 1,
"activities": [
"EXIT",
"RIDE"
]
}
]
}
```
## Case 2 solution

If we take the station bypass scenario above, we can assign the same affected activities (`BOARD` and `EXIT`) to each `stop` within each of the stations that are bypassed:

- Stop 3-7: `["BOARD", "EXIT"]`
- Stop 3-1: `["BOARD", "EXIT"]`
- Stop 4-7: `["BOARD", "EXIT"]`
- Stop 4-1: `["BOARD", "EXIT"]`
- Stop 5-7: `["BOARD", "EXIT"]`
- Stop 5-1: `["BOARD", "EXIT"]`

Image

*`informed_entity.activities` in red text*

Sample of a GTFS-Realtime alert with `informed_entity.activities`:

```json
{
"id": "123457",
"alert": {
"effect": "NO_SERVICE",
"effect_detail": "STATION_BYPASS",
"cause": "POLICE_ACTIVITY",
"cause_detail": "POLICE_ACTIVITY",
"header_text": {
"translation": [
{
"text": "Orange Line trains will not stop at Station 3, Station 4, or Station 5.",
"language": "en"
}
]
},
"description_text": {
"translation": [
{
"text": "",
"language": "en"
}
]
},
"severity_level": "SEVERE",
"active_period": [
{
"start": 1748402460,
"end": 1748409744
}
],
"informed_entity": [
{
"agency_id": "1",
"route_type": 1,
"route_id": "Orange",
"stop_id": "3-1",
"direction_id": 0,
"activities": [
"BOARD",
"EXIT"
]
},
{
"agency_id": "1",
"route_type": 1,
"route_id": "Orange",
"stop_id": "4-1",
"direction_id": 0,
"activities": [
"BOARD",
"EXIT"
]
},
{
"agency_id": "1",
"route_type": 1,
"route_id": "Orange",
"stop_id": "5-1",
"direction_id": 0,
"activities": [
"BOARD",
"EXIT"
]
},
{
"agency_id": "1",
"route_type": 1,
"route_id": "Orange",
"stop_id": "3-7",
"direction_id": 1,
"activities": [
"BOARD",
"EXIT"
]
},
{
"agency_id": "1",
"route_type": 1,
"route_id": "Orange",
"stop_id": "4-7",
"direction_id": 1,
"activities": [
"BOARD",
"EXIT"
]
},
{
"agency_id": "1",
"route_type": 1,
"route_id": "Orange",
"stop_id": "5-7",
"direction_id": 1,
"activities": [
"BOARD",
"EXIT"
]
}
]
}
```

### Additional information

The MBTA (@natekauf, @jfabi), in partnership with our alerts tooling vendor Arcadis (@dan-engler-arcadis), has been using `activities` in `informed_entities` in our enhanced GTFS feed in our production environment for several years, and it has been integral in enabling internal tools to solve the problems described above. We are excited by the prospect of third-party applications being able to present the same kind of nuances in service disruptions.

The MBTA and Arcadis have also extended `activities` to satisfy other use cases. Beyond `BOARD`, `EXIT`, and `RIDE`, we use `activities` to describe access-related activities that are affected by an alert. For example:

- An alert about elevator maintenance that would disrupt wheelchair use while boarding or exiting would include `USING_WHEELCHAIR` in its `activities`.

Arcadis’s [TRANSIT-alerts GTFS-realtime documentation](https://transit-alerts-documentation.s3.amazonaws.com/IBI_TRANSIT-alerts_GTFS-realtime_Documentation.pdf) section on activities (pages 15-16) includes specifics about the other alert activities related to facilities, namely `USING_WHEELCHAIR`, `USING_ESCALATOR`, `BRINGING_BIKE`, `STORE_BIKE`, and `PARK_CAR`, and the hierarchical nature of activities.

Examples of activities can be found in our live enhanced GTFS feed here: https://cdn.mbta.com/realtime/Alerts_enhanced.json. Documentation of the feed can be found [here](https://github.com/mbta/gtfs-documentation/blob/master/reference/gtfs-realtime.md#enhanced-json-feeds).

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.