Skip to main content

trips_updated

event type: com.mbta.ctd.glides.trips_updated.v1

Published when Glides has new information about trips, for example operator assignments or dropped trips. Consumers who want to know what trains are running should pay attention to this event, and don't need to pay attention to any other events.

Data

Fields in the event's data:

  • metadata (Metadata): how the updates were entered in Glides, including the inspector who made the change and the location of the trainsheet.
  • tripUpdates (array of (TripUpdated|TripAdded)): The list of one or more trips that have new information.

Car

Fields:

  • label (string | "none", optional): car number corresponding to the GTFS-RT label field. Or "none" if the inspector has unassigned the car. If the field is absent, it is not modified.
  • operator (Operator | "none" | "unset", optional): the operator assigned to this car. The string "none" means the inspector has unassigned the operator without reassigning another. The string "unset" means to discard the previous value as if the field had never been modified. If the field is absent, it is not modified from its previous value.

"unset" and "none" are semantically different, and used consistently with the "unset" values in TripUpdated. If an operator is "unset", then, as if no update had ever been made, clients SHOULD assume the scheduled operator will operate the car. If an operator is "none", then we don't know who will operate the car.

An empty object {} is valid if nothing about the car has been modified.

The length of cars always reflects the known length of the train.

DroppedReason

An object representing the reason that a trip was dropped. The presence of this object implies that the trip was dropped.

Fields:

  • reason (string): free-text description about why a trip was dropped.

Currently the reason is entered by inspectors in a free-text field. It's published in an object so that if Glides collects more structured data in the future, then extra fields can be added. If more fields are added, then a generated text description would be filled into the reason field, and it would not be a breaking change.

reason MAY be the empty string if for some reason Glides does not have information about why a trip was dropped.

Location

See Location

Metadata

See Metadata

Operator

See Operator

Scheduled

Scheduled information about the trip. It was not updated in Glides, but is included in the event stream so that consumers can know the schedule information that Glides uses. If data here was never overriden by a corresponding field in TripUpdated, then consumers can assume that the trip operated based on the scheduled information contained here.

Fields:

  • scheduledCars (array of ScheduledCar): Array of length 1 or 2. The length reflects the scheduled length of the train. In a 2 car train, the front car is listed first.

It does not include time and location fields, because for scheduled trips those fields are already in TripKey

ScheduledCar

Fields:

  • run (string, optional): The run number scheduled to the trip.
  • operator (Operator, optional): The operator who is scheduled to operate the run that day, and therefore scheduled to do the trip.

If fields are missing from ScheduledCar, it is not known who is scheduled to operate that car. An empty object is valid if we know the car is scheduled to operate but don't know anything else about it.

Time

Time in the HH:MM:SS format. The time is measured from "noon minus 12h" of the service day (effectively midnight except for days on which daylight savings time changes occur). For times occurring after midnight, enter the time as a value greater than 24:00:00 in HH:MM:SS local time for the day on which the trip schedule begins. Effectively, a GTFS Time but without support for H:MM:SS times.

Example: 04:30:00 for 4:30AM or 25:35:00 for 1:35AM on the next day.

TripAdded

There is a new trip, that does not appear in the Glides' schedule data. "Added" is relative to the schedule that Glides uses, and an added trip may correspond to a trip that appears in a different schedule.

Any added trips will appear exactly once as a TripAdded object, and any future updates will appear as TripUpdated objects. (But note: Clients MUST tolerate updates for trips they haven't seen due to network errors or the Kinesis trim horizon, see: Short-term storage. And clients MUST tolerate duplicates due to a network error, see: Idempotence.)

The event SHOULD only include values which were explicitly included by the author: inferred values SHOULD NOT be included.

TripAdded objects are the same as TripUpdated with the following new restrictions, so that enough is specified about the trip to know or infer where and when the trip will happen. (This extension means all TripAdded objects also happen to be valid TripUpdated objects according to the spec below.)

New fields:

  • previousTripKey (TripKey, conditionally required): The added trip will happen immediately after the trip referred to by previousTripKey. Required if startTime and endTime are both not set. (If no time is specified, then the previous trip is necessary so the trip's time can be inferred.) This field MAY refer to a trip that has not been already seen in the event stream.

New restrictions on existing fields:

  • type (string): MUST be "added" (as opposed to "updated").
  • tripKey (TripKey): will always be the added trip form, and never the scheduled trip form.
  • startLocation (Location, conditionally required): where the trip will start. Required if startTime is specified.
  • endLocation (Location, conditionally required): where the trip will end. Required if endTime is specified.
  • At least one of startLocation and endLocation is required.
  • At least one of startTime, endTime, and previousTripKey is required.
  • revenue ("revenue" | "nonrevenue", optional): If this field is missing when adding a trip, the default is that the trip is in revenue service.
  • dropped SHOULD NOT be set.
  • All data SHOULD NOT be "none" or "unset". (Instead, the fields would not be included).

Glides SHOULD include the cars field to indicate the length of the train, even if no information is known about each car.

TripKey

The event has different ways to label trips that are added or scheduled in Glides' schedule.

The added/scheduled distinction is according to the schedule in Glides. RTR and GTFS may have a different schedule than Glides (due to disruptions, for example), so a trip that Glides thinks is scheduled may not match up with scheduled trip in GTFS, and RTR may decide that a trip that was added in Glides lines up close enough to correspond to a scheduled trip in GTFS.

For added trips, Glides makes up a new ID, which is kept the same for any subsequent updates to the same added trip.

For scheduled trips, because Glides might be using a different schedule than any consumer, Glides provides the time and location of the trip, according to its own schedule. Glides also provides a tripId which is intended to line up to the trip IDs in GTFS most of the time, because they're derived from the same source (HASTUS's trp_int_number).

Consumers MAY check tripId to help match trips in this feed to GTFS. If a consumer sees a tripId in this feed that also appears in GTFS on a trip on the same service date, it refers to the same trip (even if the given scheduled times aren't quite the same). If a tripId for a trip in this feed does not appear on any trip in GTFS (or if the tripId field is missing, or if a consumer doesn't check the tripId field), then the consumer may use the date, time, and location of the trip to try to associate it to a similar trip in whatever schedule it's using, or a consumer may treat the trip as if does not correspond to any trip in the consumer's schedule.

tripId is optional because it was added as a backwards-compatible change. Glides SHOULD include it in all future data.

Added Trip

  • serviceDate (RFC3999 date): the service date for the trip.
  • glidesId (string): unique value representing this trip for the given serviceDate.

Example:

{ "serviceDate": "2023-01-20", "glidesId": "ADDED-123" }

Scheduled Trip

  • serviceDate (RFC3999 date): the service date for the trip.
  • tripId (string, optional): ID, unique within the service date. Intended to match GTFS trip IDs, but may not.
  • startLocation (Location): where the trip is scheduled to start.
  • endLocation (Location): where the trip is scheduled to end.
  • startTime (Time): when the trip is scheduled to depart startLocation.
  • endTime (Time): when the trip is scheduled to arrive at endLocation.
  • revenue ("revenue" | "nonrevenue", optional): Whether the trip is scheduled to be in revenue service. If this field is missing, consumers SHOULD assume the trip is scheduled to be in revenue service.

Example:

{
"serviceDate": "2023-01-20",
"tripId": "64100439",
"startLocation": { "gtfsId": "place-mdftf" },
"endLocation": { "gtfsId": "place-heath" },
"startTime": "04:47:00",
"endTime": "05:34:00"
}

TripUpdated

This indicates that a trip was updated in some fashion: e.g. consist, operators, departure time. The trip is either a scheduled trip, or an added trip that has already appeared in the events stream. A field that is not present was not updated.

Fields in the object:

  • type (string): "updated"|"added". If this field is "updated", the object is this TripUpdated object. If it's "added", it's a TripAdded object that extends TripUpdated and has all these fields but with additional meaning, fields, and restrictions, see above. Subsequent updates to previously-added trips have type "updated".
  • tripKey (TripKey): which trip is being updated.
  • comment (string, optional): free text information about the trip. Could potentially be the empty string, if a comment was deleted.
  • startLocation (Location | "unset", optional): the new destination of the train.
  • endLocation (Location | "unset", optional): the new destination of the train.
  • startTime (Time | "unset", optional): if present, the new time that the train is expected to depart startLocation (or the existing startLocation of the trip).
  • endTime (Time | "unset", optional): if present, the new time that the train is expected to arrive at endLocation (or the existing endLocation of the trip).
  • cars (array of Car, optional): array of length 1 or 2, containing the car numbers and operators for each car in the train assigned to the trip. If absent, there are no changes to any cars. If present, the length of the array is the length of the train. In a two car train, the front car is listed first.
  • revenue ("revenue" | "nonrevenue", optional): Whether the trip is in revenue service.
  • dropped (DroppedReason | false, optional): If present the trip was dropped for the provided reason. If set to false, the trip is not dropped (and restored if previously dropped).
  • scheduled (Scheduled | null): For trips in Glides' schedule, this represents the scheduled data for the trip. It will always be present and won't change between subsequent updates to the same trip. For added trips, this will always be null.

Some values might be the special string "unset". This means to treat the field as if it had never been modified. This is semantically slightly different than setting the value to the scheduled value. For example, setting startTime to "unset" implies we don't know when the trip will leave, and the scheduled time might be a good guess, but setting startTime to equal the scheduled start time implies that an inspector has confirmed the trip will leave at that time.

Notes:

  • setting a new location or time does not modify the TripKey for a scheduled trip.
  • If cars is updated from a 1-element list to a 2-element list, then Glides SHOULD include data for the 2nd car. This is relevant if a two-car train has a car removed and then re-added. If a field was set before the car was dropped, then when the car is restored, clients MUST assume that the field is "none" as opposed to retaining its previous value, but Glides SHOULD include the data to avoid the ambiguity.
  • Some fields, such as startTime or cars, are not relevant to dropped trips. Those fields SHOULD NOT be set in an update that drops a trip or any following updates, until the trip is undropped by setting dropped to false. However, if a trip is undropped, clients MUST assume all fields retain their values from before the field was undropped. Clients MUST NOT ignore updates to fields when a trip is dropped, even if they aren't relevant for dropped trips. For example, if a trip is dropped, and then the startTime is updated, and then it's undropped, the trip's startTime is the value set while the trip was dropped. Glides MAY include extra fields in an update that undrops a trip, if they are changed as part of the same event that undropped the trip, or just to remind clients about them now that they're relevant.

Examples

Inspector Alice (badge number: 123) is working at Mattapan. The 1:30am trip is being held 15 minutes to wait for a final Red Line train.

Note that the date of the the event is 2023-01-23, but the service date is 2023-01-22. The hour in the time itself is greater than 24 hours, to reflect that the time is the next calendar day.

{
"type": "com.mbta.ctd.glides.trips_updated.v1",
"specversion": "1.0",
"source": "glides.mbta.com",
"id": "19fdb184-7dd6-4664-8472-04bd6177ec44",
"time": "2023-01-23T01:25:00-05:00",
"data": {
"metadata": {
"inputType": "edit-trip"
},
"tripUpdates": [
{
"type": "updated",
"tripKey": {
"serviceDate": "2023-01-22",
"tripId": "64085858",
"startLocation": {
"gtfsId": "place-matt"
},
"endLocation": {
"gtfsId": "place-ashmt"
},
"startTime": "25:30:00",
"endTime": "25:38:00"
},
"startTime": "25:45:00",
"scheduled": {
"scheduledCars": [
{
"run": "500",
"operator": {
"badgeNumber": "1234"
}
}
]
}
}
]
}
}

Schema

Loading com.mbta.ctd.glides.trips_updated.v1...

Unsupported Features

Mid-route data

This event has no way to publish data about the middle of trips, only the endpoints. This is because Glides does not currently collect data from inspectors about the middles of trips. It's likely that in the future, Glides might add features to allow Chief Inspectors, Dispatchers, or others to input short turns, holds, expresses, or other adjustments, in which case this event would be updated or another event would be added.

More specific events

This event lumps all service updates into a single event. Other proposals considered having separate events for trip_added, trip_dropped, or even separate events for updating each field. This would have portrayed inspectors' intent more clearly, and allowed more specific data to be sent in each case. However, it is easier for consumers to understand the effects on service from this single state-transfer event. Consumers who want more transparency into how an official entered the update in Glides should look at the metadata.inputType field. For more explanation, see the alternatives section of RFC 18.

Include all known data, not just changes

This event only includes updated fields, which means that clients must listen and remember all past changes if they want to know the state of a trip. In the future, if a client needs it, Glides could start including in this event a snapshot of all known data about the trip, but there hasn't been a concrete reason to add it yet. For more explanation, see the alternatives section of RFC 18. See also: Kinds of Events