diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md
index 164a9a80..7d4737d6 100644
--- a/gtfs/spec/en/reference.md
+++ b/gtfs/spec/en/reference.md
@@ -40,6 +40,9 @@ This document defines the format and structure of the files that comprise a GTFS
- [location_group_stops.txt](#location_group_stopstxt)
- [locations.geojson](#locationsgeojson)
- [booking_rules.txt](#booking_rulestxt)
+ - [notices.txt](#noticestxt)
+ - [notice\_assignments.txt](#notice_assignmentstxt)
+ - [trip\_segments.txt](#trip_segmentstxt)
- [translations.txt](#translationstxt)
- [feed\_info.txt](#feed_infotxt)
- [attributions.txt](#attributionstxt)
@@ -144,6 +147,9 @@ This specification defines the following files:
| [location_group_stops.txt](#location_group_stopstxt) | Optional | Rules to assign stops to location groups. |
| [locations.geojson](#locationsgeojson) | Optional | Zones for rider pickup or drop-off requests by on-demand services, represented as GeoJSON polygons. |
| [booking_rules.txt](#booking_rulestxt) | Optional | Booking information for rider-requested services. |
+| [notices.txt](#noticestxt) | Optional | Notices to be displayed to riders for specific routes, trips, or stops. |
+| [notice_assignments.txt](#notice_assignmentstxt) | **Conditionally Required** | Assignments of notices or notice groups to routes, trips, or stops.
Conditionally Required:
- **Required** if [notices.txt](#noticestxt) is provided. |
+| [trip_segments.txt](#trip_segmentstxt) | Optional | Defines segments of trips by stop sequence range, for use in notice assignments. |
| [translations.txt](#translationstxt) | Optional | Translations of customer-facing dataset values. |
| [feed_info.txt](#feed_infotxt) | **Conditionally Required** | Dataset metadata, including publisher, version, and expiration information.
Conditionally Required:
- **Required** if [translations.txt](#translationstxt) is provided.
- Recommended otherwise.|
| [attributions.txt](#attributionstxt) | Optional | Dataset attributions. |
@@ -849,6 +855,61 @@ Defines the booking rules for rider-requested services
| `info_url` | URL | Optional | URL providing information about the booking rule. |
| `booking_url` | URL | Optional | URL to an online interface or app where the booking request can be made. |
+### notices.txt
+
+File: **Optional**
+
+Primary key (`notice_id`)
+
+Defines notices that can be displayed to riders. These can be attached to one or more entities with `notice_assignments.txt`.
+
+These notices are additional textual messages that can improve results with human-readable information. As opposed to GTFS Realtime Service Alerts, they are already known during conceptual planning and therefore are not "real-time".
+
+It should not replace machine-readable information like pick up/drop off types or fare data.
+
+| Field Name | Type | Presence | Description |
+| ------ | ------ | ------ | ------ |
+| `notice_id` | Unique ID | **Required** | Identifies a notice. |
+| `notice_group_id` | ID | Optional | Groups notices together. The same `notice_group_id` may be assigned to multiple notices. A `notice_group_id` can be referenced in [notice_assignments.txt](#notice_assignmentstxt) to assign all notices in the group at once. |
+| `display_text` | Text | **Required** | Text of the notice to be displayed to riders. HTML formatting characters are not permitted. |
+
+### notice_assignments.txt
+
+File: **Conditionally Required**
+
+Primary key (`*`)
+
+Assigns notices or notice groups defined in [notices.txt](#noticestxt) to routes, trips in their entirety, or individual stops.
+
+Specifically, attaching them means the following:
+
+- route: the notice applies to _all_ trips in the route. If you want to assign to a specific trip use a `table_name` with value `trip`
+- trip: the notice applies to a specific trip in its entirety, not to individual hops.
+- trip segment: the notice applies to part of a trip.
+- stop: the notice applies to a stop but completely decoupled from a specific trip. It is not intended for notices that target stop times.
+
+| Field Name | Type | Presence | Description |
+| ------ | ------ | ------ | ------ |
+| `notice_id` | Foreign ID referencing `notices.notice_id` | **Conditionally Required** | Identifies the notice to assign.
Conditionally Required:
- **Required** if `notice_group_id` is not defined.
- **Forbidden** if `notice_group_id` is defined. |
+| `notice_group_id` | Foreign ID referencing `notices.notice_group_id` | **Conditionally Required** | Identifies the notice group to assign. All notices sharing this `notice_group_id` in [notices.txt](#noticestxt) are assigned.
Conditionally Required:
- **Required** if `notice_id` is not defined.
- **Forbidden** if `notice_id` is defined. |
+| `table_name` | Enum | **Required** | Identifies the table containing the record to which the notice is assigned. Valid options are:
`routes` - Record is in [routes.txt](#routestxt).
`trips` - Record is in [trips.txt](#tripstxt).
`stops` - Record is in [stops.txt](#stopstxt).
`trip_segments` - Record is in [trip_segments.txt](#trip_segmentstxt). |
+| `record_id` | Foreign ID | **Required** | Primary key of the record in the table specified by `table_name` to which the notice is assigned. For `table_name=routes` use `route_id`; for `table_name=trips` use `trip_id`; for `table_name=stops` use `stop_id`; for `table_name=trip_segments` use `trip_segment_id`. |
+
+### trip_segments.txt
+
+File: **Optional**
+
+Primary key (`trip_segment_id`)
+
+Defines a contiguous segment of a trip by specifying an inclusive range of stop sequences. Segments defined here can be referenced in [notice_assignments.txt](#notice_assignmentstxt) to apply a notice to a portion of a trip.
+
+| Field Name | Type | Presence | Description |
+| ------ | ------ | ------ | ------ |
+| `trip_segment_id` | Unique ID | **Required** | Identifies a trip segment. |
+| `trip_id` | Foreign ID referencing `trips.trip_id` | **Required** | Identifies the trip to which the segment belongs. |
+| `from_stop_sequence` | Non-negative integer | **Required** | The `stop_sequence` value of the first stop of the segment (inclusive). Must refer to a `stop_sequence` value in [stop_times.txt](#stop_timestxt) for the given `trip_id`. |
+| `to_stop_sequence` | Non-negative integer | **Required** | The `stop_sequence` value of the last stop of the segment (inclusive). Must refer to a `stop_sequence` value in [stop_times.txt](#stop_timestxt) for the given `trip_id`. Must be greater than or equal to `from_stop_sequence`. |
+
### translations.txt
File: **Optional**
@@ -859,15 +920,15 @@ In regions that have multiple official languages, transit agencies/operators typ
If both referencing methods (`record_id`, `record_sub_id`) and `field_value` are used to translate the same value in 2 different rows, the translation provided with (`record_id`, `record_sub_id`) takes precedence.
-| Field Name | Type | Presence | Description |
-| ------ | ------ | ------ | ------ |
-| `table_name` | Enum | **Required** | Defines the table that contains the field to be translated. Allowed values are:
- `agency`
- `stops`
- `routes`
- `trips`
- `stop_times`
- `pathways`
- `levels`
- `feed_info`
- `attributions`
Any file added to GTFS will have a `table_name` value equivalent to the file name, as listed above (i.e., not including the `.txt` file extension). |
-| `field_name` | Text | **Required** | Name of the field to be translated. Fields with type `Text` may be translated, fields with type `URL`, `Email` and `Phone number` may also be “translated” to provide resources in the correct language. Fields with other types should not be translated. |
-| `language` | Language code | **Required** | Language of translation.
If the language is the same as in `feed_info.feed_lang`, the original value of the field will be assumed to be the default value to use in languages without specific translations (if `default_lang` doesn't specify otherwise).
_Example: In Switzerland, a city in an officially bilingual canton is officially called “Biel/Bienne”, but would simply be called “Bienne” in French and “Biel” in German._ |
-| `translation` | Text or URL or Email or Phone number | **Required** | Translated value. |
-| `record_id` | Foreign ID | **Conditionally Required** | Defines the record that corresponds to the field to be translated. The value in `record_id` must be the first or only field of a table's primary key, as defined in the primary key attribute for each table and below:
- `agency_id` for [agency.txt](#agencytxt)
- `stop_id` for [stops.txt](#stopstxt);
- `route_id` for [routes.txt](#routestxt);
- `trip_id` for [trips.txt](#tripstxt);
- `trip_id` for [stop_times.txt](#stop_timestxt);
- `pathway_id` for [pathways.txt](#pathwaystxt);
- `level_id` for [levels.txt](#levelstxt);
- `attribution_id` for [attributions.txt](#attributionstxt).
Fields in tables not defined above should not be translated. However producers sometimes add extra fields that are outside the official specification and these unofficial fields may be translated. Below is the recommended way to use `record_id` for those tables:
- `service_id` for [calendar.txt](#calendartxt);
- `service_id` for [calendar_dates.txt](#calendar_datestxt);
- `fare_id` for [fare_attributes.txt](#fare_attributestxt);
- `fare_id` for [fare_rules.txt](#fare_rulestxt);
- `shape_id` for [shapes.txt](#shapestxt);
- `trip_id` for [frequencies.txt](#frequenciestxt);
- `from_stop_id` for `transfers.txt`.
Conditionally Required:
- **Forbidden** if `table_name` is `feed_info`.
- **Forbidden** if `field_value` is defined.
- **Required** if `field_value` is empty. |
-| `record_sub_id` | Foreign ID | **Conditionally Required** | Helps the record that contains the field to be translated when the table doesn’t have a unique ID. Therefore, the value in `record_sub_id` is the secondary ID of the table, as defined by the table below:
- None for [agency.txt](#agencytxt);
- None for [stops.txt](#stopstxt);
- None for [routes.txt](#routestxt);
- None for [trips.txt](#tripstxt);
- `stop_sequence` for [stop_times.txt](#stop_timestxt);
- None for [pathways.txt](#pathwaystxt);
- None for [levels.txt](#levelstxt);
- None for [attributions.txt](#attributionstxt).
Fields in tables not defined above should not be translated. However producers sometimes add extra fields that are outside the official specification and these unofficial fields may be translated. Below is the recommended way to use `record_sub_id` for those tables:
- None for [calendar.txt](#calendartxt);
- `date` for [calendar_dates.txt](#calendar_datestxt);
- None for [fare_attributes.txt](#fare_attributestxt);
- `route_id` for [fare_rules.txt](#fare_rulestxt);
- None for [shapes.txt](#shapestxt);
- `start_time` for [frequencies.txt](#frequenciestxt);
- `to_stop_id` for [transfers.txt](#transferstxt).
Conditionally Required:
- **Forbidden** if `table_name` is `feed_info`.
- **Forbidden** if `field_value` is defined.
- **Required** if `table_name=stop_times` and `record_id` is defined. |
-| `field_value` | Text or URL or Email or Phone number | **Conditionally Required** | Instead of defining which record should be translated by using `record_id` and `record_sub_id`, this field can be used to define the value which should be translated. When used, the translation will be applied when the fields identified by `table_name` and `field_name` contains the exact same value defined in field_value.
The field must have **exactly** the value defined in `field_value`. If only a subset of the value matches `field_value`, the translation won’t be applied.
If two translation rules match the same record (one with `field_value`, and the other one with `record_id`), the rule with `record_id` takes precedence.
Conditionally Required:
- **Forbidden** if `table_name` is `feed_info`.
- **Forbidden** if `record_id` is defined.
- **Required** if `record_id` is empty. |
+| Field Name | Type | Presence | Description |
+| ------ | ------ | ------ |------|
+| `table_name` | Enum | **Required** | Defines the table that contains the field to be translated. Allowed values are:
- `agency`
- `stops`
- `routes`
- `trips`
- `stop_times`
- `pathways`
- `levels`
- `feed_info`
- `attributions`
- `notices`
Any file added to GTFS will have a `table_name` value equivalent to the file name, as listed above (i.e., not including the `.txt` file extension). |
+| `field_name` | Text | **Required** | Name of the field to be translated. Fields with type `Text` may be translated, fields with type `URL`, `Email` and `Phone number` may also be “translated” to provide resources in the correct language. Fields with other types should not be translated. |
+| `language` | Language code | **Required** | Language of translation.
If the language is the same as in `feed_info.feed_lang`, the original value of the field will be assumed to be the default value to use in languages without specific translations (if `default_lang` doesn't specify otherwise).
_Example: In Switzerland, a city in an officially bilingual canton is officially called “Biel/Bienne”, but would simply be called “Bienne” in French and “Biel” in German._ |
+| `translation` | Text or URL or Email or Phone number | **Required** | Translated value. |
+| `record_id` | Foreign ID | **Conditionally Required** | Defines the record that corresponds to the field to be translated. The value in `record_id` must be the first or only field of a table's primary key, as defined in the primary key attribute for each table and below:
- `agency_id` for [agency.txt](#agencytxt)
- `stop_id` for [stops.txt](#stopstxt);
- `route_id` for [routes.txt](#routestxt);
- `trip_id` for [trips.txt](#tripstxt);
- `trip_id` for [stop_times.txt](#stop_timestxt);
- `pathway_id` for [pathways.txt](#pathwaystxt);
- `level_id` for [levels.txt](#levelstxt);
- `attribution_id` for [attributions.txt](#attributionstxt);
- `notice_id` for [notices.txt](#noticestxt).
Fields in tables not defined above should not be translated. However producers sometimes add extra fields that are outside the official specification and these unofficial fields may be translated. Below is the recommended way to use `record_id` for those tables:
- `service_id` for [calendar.txt](#calendartxt);
- `service_id` for [calendar_dates.txt](#calendar_datestxt);
- `fare_id` for [fare_attributes.txt](#fare_attributestxt);
- `fare_id` for [fare_rules.txt](#fare_rulestxt);
- `shape_id` for [shapes.txt](#shapestxt);
- `trip_id` for [frequencies.txt](#frequenciestxt);
- `from_stop_id` for `transfers.txt`.
Conditionally Required:
- **Forbidden** if `table_name` is `feed_info`.
- **Forbidden** if `field_value` is defined.
- **Required** if `field_value` is empty. |
+| `record_sub_id` | Foreign ID | **Conditionally Required** | Helps the record that contains the field to be translated when the table doesn’t have a unique ID. Therefore, the value in `record_sub_id` is the secondary ID of the table, as defined by the table below:
- None for [agency.txt](#agencytxt);
- None for [stops.txt](#stopstxt);
- None for [routes.txt](#routestxt);
- None for [trips.txt](#tripstxt);
- `stop_sequence` for [stop_times.txt](#stop_timestxt);
- None for [pathways.txt](#pathwaystxt);
- None for [levels.txt](#levelstxt);
- None for [attributions.txt](#attributionstxt).
Fields in tables not defined above should not be translated. However producers sometimes add extra fields that are outside the official specification and these unofficial fields may be translated. Below is the recommended way to use `record_sub_id` for those tables:
- None for [calendar.txt](#calendartxt);
- `date` for [calendar_dates.txt](#calendar_datestxt);
- None for [fare_attributes.txt](#fare_attributestxt);
- `route_id` for [fare_rules.txt](#fare_rulestxt);
- None for [shapes.txt](#shapestxt);
- `start_time` for [frequencies.txt](#frequenciestxt);
- `to_stop_id` for [transfers.txt](#transferstxt).
Conditionally Required:
- **Forbidden** if `table_name` is `feed_info`.
- **Forbidden** if `field_value` is defined.
- **Required** if `table_name=stop_times` and `record_id` is defined. |
+| `field_value` | Text or URL or Email or Phone number | **Conditionally Required** | Instead of defining which record should be translated by using `record_id` and `record_sub_id`, this field can be used to define the value which should be translated. When used, the translation will be applied when the fields identified by `table_name` and `field_name` contains the exact same value defined in field_value.
The field must have **exactly** the value defined in `field_value`. If only a subset of the value matches `field_value`, the translation won’t be applied.
If two translation rules match the same record (one with `field_value`, and the other one with `record_id`), the rule with `record_id` takes precedence.
Conditionally Required:
- **Forbidden** if `table_name` is `feed_info`.
- **Forbidden** if `record_id` is defined.
- **Required** if `record_id` is empty. |
### feed_info.txt