From fec8338bf6fa1eb684188cccdd65fb0ec433455c Mon Sep 17 00:00:00 2001 From: Guillaume Campagna Date: Wed, 4 Feb 2026 14:17:38 -0500 Subject: [PATCH 01/13] Add carriage_positions.txt specification Defines optimal carriage positioning for transfers and platform exits. Enables trip planners to recommend which carriage to board for minimal walking time at destinations. Fields: - from_stop_id: boarding platform - to_stop_id: destination stop/facility - recommended_carriage: 1-indexed from front - carriage_count: total positions (can be logical) - front_car_position: left/right platform side - facility_type: elevator/escalator/stairs (optional) Placed after pathways.txt as it complements station navigation. --- gtfs/spec/en/reference.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md index b4569a54..c2ed7031 100644 --- a/gtfs/spec/en/reference.md +++ b/gtfs/spec/en/reference.md @@ -35,6 +35,7 @@ This document defines the format and structure of the files that comprise a GTFS - [frequencies.txt](#frequenciestxt) - [transfers.txt](#transferstxt) - [pathways.txt](#pathwaystxt) + - [carriage_positions.txt](#carriage_positionstxt) - [levels.txt](#levelstxt) - [location_groups.txt](#location_groupstxt) - [location_group_stops.txt](#location_group_stopstxt) @@ -139,6 +140,7 @@ This specification defines the following files: | [frequencies.txt](#frequenciestxt) | Optional | Headway (time between trips) for headway-based service or a compressed representation of fixed-schedule service. | | [transfers.txt](#transferstxt) | Optional | Rules for making connections at transfer points between routes. | | [pathways.txt](#pathwaystxt) | Optional | Pathways linking together locations within stations. | +| [carriage_positions.txt](#carriage_positionstxt) | Optional | Optimal carriage positioning for transfers and platform exits. | | [levels.txt](#levelstxt) | **Conditionally Required** | Levels within stations.

Conditionally Required:
- **Required** when describing pathways with elevators (`pathway_mode=5`).
- Optional otherwise. | | [location_groups.txt](#location_groupstxt) | Optional | A group of stops that together indicate locations where a rider may request pickup or drop off. | | [location_group_stops.txt](#location_group_stopstxt) | Optional | Rules to assign stops to location groups. | @@ -747,6 +749,27 @@ Pathways are intended to exhaustively define the internal access graph of a stat | `signposted_as` | Text | Optional | Public facing text from physical signage that is visible to riders.

May be used to provide text directions to riders, such as 'follow signs to '. The text in `singposted_as` should appear exactly how it is printed on the signs.

When the physical signage is multilingual, this field may be populated and translated following the example of `stops.stop_name` in the field definition of `feed_info.feed_lang`.| | `reversed_signposted_as` | Text | Optional | Same as `signposted_as`, but when the pathway is used from the `to_stop_id` to the `from_stop_id`.| +### carriage_positions.txt + +File: **Optional** + +Primary key (`from_stop_id`, `to_stop_id`, `facility_type`) + +Defines optimal carriage positioning for transfers and platform exit access. Enables trip planners to recommend which carriage passengers should board to minimize walking time at their destination. + +While [pathways.txt](#pathwaystxt) handles navigation within stations, it does not address where to stand on the platform before boarding. This file complements pathways by providing carriage-level boarding recommendations. + +Producers MAY use logical carriage divisions when exact carriage positions are unavailable. For example, `carriage_count=3` with `recommended_carriage=1` indicates "board near the front" regardless of actual vehicle length. + +| Field Name | Type | Presence | Description | +| ------ | ------ | ------ | ------ | +| `from_stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the platform where the passenger boards. Must reference a stop with `location_type=0`. | +| `to_stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the destination: a transfer platform, station entrance, or exit. Must reference a stop with `location_type=0` or `location_type=2`. | +| `recommended_carriage` | Non-negative integer | **Required** | The recommended carriage to board, 1-indexed from the front of the vehicle. May represent a logical position rather than exact carriage number. Must be less than or equal to `carriage_count`. | +| `carriage_count` | Non-negative integer | **Required** | Number of carriage positions in this configuration. May represent logical divisions (e.g., 3 for front/middle/back) rather than actual carriage count. | +| `front_car_position` | Enum | **Required** | Platform side where the front carriage (carriage 1) stops, from the perspective of a passenger facing the track. Valid options are:

`left` - Front carriage stops on the left side of the platform.
`right` - Front carriage stops on the right side of the platform. | +| `facility_type` | Enum | Optional | Type of facility at the destination. Valid options are:

`elevator` - Elevator access.
`escalator` - Escalator access.
`stairs` - Stair access.

May be empty if the destination is another platform or general exit. | + ### levels.txt File: **Conditionally Required** From 7331df24e4e02c6a3cf73c7c3589dc2f065ed2fb Mon Sep 17 00:00:00 2001 From: Guillaume Campagna Date: Thu, 5 Feb 2026 09:55:15 -0500 Subject: [PATCH 02/13] Clarify field descriptions for front_car_position and facility_type Address PR review feedback by specifying stop_id references. Co-Authored-By: Claude Opus 4.5 --- gtfs/spec/en/reference.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md index c2ed7031..daf6a9c3 100644 --- a/gtfs/spec/en/reference.md +++ b/gtfs/spec/en/reference.md @@ -767,8 +767,8 @@ Producers MAY use logical carriage divisions when exact carriage positions are u | `to_stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the destination: a transfer platform, station entrance, or exit. Must reference a stop with `location_type=0` or `location_type=2`. | | `recommended_carriage` | Non-negative integer | **Required** | The recommended carriage to board, 1-indexed from the front of the vehicle. May represent a logical position rather than exact carriage number. Must be less than or equal to `carriage_count`. | | `carriage_count` | Non-negative integer | **Required** | Number of carriage positions in this configuration. May represent logical divisions (e.g., 3 for front/middle/back) rather than actual carriage count. | -| `front_car_position` | Enum | **Required** | Platform side where the front carriage (carriage 1) stops, from the perspective of a passenger facing the track. Valid options are:

`left` - Front carriage stops on the left side of the platform.
`right` - Front carriage stops on the right side of the platform. | -| `facility_type` | Enum | Optional | Type of facility at the destination. Valid options are:

`elevator` - Elevator access.
`escalator` - Escalator access.
`stairs` - Stair access.

May be empty if the destination is another platform or general exit. | +| `front_car_position` | Enum | **Required** | Platform side where the front carriage (carriage 1) stops at `from_stop_id`, from the perspective of a passenger facing the track. Valid options are:

`left` - Front carriage stops on the left side of the platform.
`right` - Front carriage stops on the right side of the platform. | +| `facility_type` | Enum | Optional | Type of facility available close to the recommended carriage at with destination `to_stop_id`. Valid options are:

`elevator` - Elevator access.
`escalator` - Escalator access.
`stairs` - Stair access.

May be empty if the destination is another platform or general exit. | ### levels.txt From 300bc51d29bf29e7d0de31a0698cbfdfc2fce51f Mon Sep 17 00:00:00 2001 From: Guillaume Campagna Date: Thu, 5 Feb 2026 10:09:22 -0500 Subject: [PATCH 03/13] Update --- gtfs/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md index daf6a9c3..f70595f7 100644 --- a/gtfs/spec/en/reference.md +++ b/gtfs/spec/en/reference.md @@ -768,7 +768,7 @@ Producers MAY use logical carriage divisions when exact carriage positions are u | `recommended_carriage` | Non-negative integer | **Required** | The recommended carriage to board, 1-indexed from the front of the vehicle. May represent a logical position rather than exact carriage number. Must be less than or equal to `carriage_count`. | | `carriage_count` | Non-negative integer | **Required** | Number of carriage positions in this configuration. May represent logical divisions (e.g., 3 for front/middle/back) rather than actual carriage count. | | `front_car_position` | Enum | **Required** | Platform side where the front carriage (carriage 1) stops at `from_stop_id`, from the perspective of a passenger facing the track. Valid options are:

`left` - Front carriage stops on the left side of the platform.
`right` - Front carriage stops on the right side of the platform. | -| `facility_type` | Enum | Optional | Type of facility available close to the recommended carriage at with destination `to_stop_id`. Valid options are:

`elevator` - Elevator access.
`escalator` - Escalator access.
`stairs` - Stair access.

May be empty if the destination is another platform or general exit. | +| `facility_type` | Enum | Optional | Type of facility available close to the recommended carriage with destination `to_stop_id`. Valid options are:

`elevator` - Elevator access.
`escalator` - Escalator access.
`stairs` - Stair access.

May be empty if the destination is another platform or general exit. | ### levels.txt From 115cf4f50c4ec0d4ffca03bb95ab2289870a239d Mon Sep 17 00:00:00 2001 From: Guillaume Campagna Date: Mon, 23 Feb 2026 13:23:38 -0500 Subject: [PATCH 04/13] Update after discussions --- gtfs/spec/en/reference.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md index f70595f7..406421bf 100644 --- a/gtfs/spec/en/reference.md +++ b/gtfs/spec/en/reference.md @@ -35,6 +35,7 @@ This document defines the format and structure of the files that comprise a GTFS - [frequencies.txt](#frequenciestxt) - [transfers.txt](#transferstxt) - [pathways.txt](#pathwaystxt) + - [station_directions.txt](#station_directionstxt) - [carriage_positions.txt](#carriage_positionstxt) - [levels.txt](#levelstxt) - [location_groups.txt](#location_groupstxt) @@ -140,6 +141,7 @@ This specification defines the following files: | [frequencies.txt](#frequenciestxt) | Optional | Headway (time between trips) for headway-based service or a compressed representation of fixed-schedule service. | | [transfers.txt](#transferstxt) | Optional | Rules for making connections at transfer points between routes. | | [pathways.txt](#pathwaystxt) | Optional | Pathways linking together locations within stations. | +| [station_directions.txt](#station_directionstxt) | Optional | Platform direction of the front carriage at each stop. | | [carriage_positions.txt](#carriage_positionstxt) | Optional | Optimal carriage positioning for transfers and platform exits. | | [levels.txt](#levelstxt) | **Conditionally Required** | Levels within stations.

Conditionally Required:
- **Required** when describing pathways with elevators (`pathway_mode=5`).
- Optional otherwise. | | [location_groups.txt](#location_groupstxt) | Optional | A group of stops that together indicate locations where a rider may request pickup or drop off. | @@ -749,11 +751,24 @@ Pathways are intended to exhaustively define the internal access graph of a stat | `signposted_as` | Text | Optional | Public facing text from physical signage that is visible to riders.

May be used to provide text directions to riders, such as 'follow signs to '. The text in `singposted_as` should appear exactly how it is printed on the signs.

When the physical signage is multilingual, this field may be populated and translated following the example of `stops.stop_name` in the field definition of `feed_info.feed_lang`.| | `reversed_signposted_as` | Text | Optional | Same as `signposted_as`, but when the pathway is used from the `to_stop_id` to the `from_stop_id`.| +### station_directions.txt + +File: **Optional** + +Primary key (`stop_id`) + +Defines which side of the platform the front carriage stops at. This information is used alongside [carriage_positions.txt](#carriage_positionstxt) to determine boarding recommendations. When the departure and arrival stations have different front car directions, trip planners can mirror the recommended carriage accordingly. + +| Field Name | Type | Presence | Description | +| ------ | ------ | ------ | ------ | +| `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the platform. Must reference a stop with `location_type=0`. | +| `front_car_position` | Enum | **Required** | Platform side where the front carriage (carriage 1) stops, from the perspective of a passenger facing the track. Valid options are:

`left` - Front carriage stops on the left side of the platform.
`right` - Front carriage stops on the right side of the platform. | + ### carriage_positions.txt File: **Optional** -Primary key (`from_stop_id`, `to_stop_id`, `facility_type`) +Primary key (`stop_id`, `to_stop_id`, `facility_type`) Defines optimal carriage positioning for transfers and platform exit access. Enables trip planners to recommend which carriage passengers should board to minimize walking time at their destination. @@ -763,12 +778,11 @@ Producers MAY use logical carriage divisions when exact carriage positions are u | Field Name | Type | Presence | Description | | ------ | ------ | ------ | ------ | -| `from_stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the platform where the passenger boards. Must reference a stop with `location_type=0`. | -| `to_stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the destination: a transfer platform, station entrance, or exit. Must reference a stop with `location_type=0` or `location_type=2`. | -| `recommended_carriage` | Non-negative integer | **Required** | The recommended carriage to board, 1-indexed from the front of the vehicle. May represent a logical position rather than exact carriage number. Must be less than or equal to `carriage_count`. | -| `carriage_count` | Non-negative integer | **Required** | Number of carriage positions in this configuration. May represent logical divisions (e.g., 3 for front/middle/back) rather than actual carriage count. | -| `front_car_position` | Enum | **Required** | Platform side where the front carriage (carriage 1) stops at `from_stop_id`, from the perspective of a passenger facing the track. Valid options are:

`left` - Front carriage stops on the left side of the platform.
`right` - Front carriage stops on the right side of the platform. | -| `facility_type` | Enum | Optional | Type of facility available close to the recommended carriage with destination `to_stop_id`. Valid options are:

`elevator` - Elevator access.
`escalator` - Escalator access.
`stairs` - Stair access.

May be empty if the destination is another platform or general exit. | +| `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the arrival platform. Must reference a stop with `location_type=0`. | +| `to_stop_id` | Foreign ID referencing `stops.stop_id` | Optional | Identifies a specific destination: a transfer platform, station entrance, or exit. Must reference a stop with `location_type=0` or `location_type=2`. When empty, the recommendation applies as a general default for the station. When provided, it gives a destination-specific recommendation that takes priority over the general default. | +| `recommended_carriage` | Positive integer | **Required** | The recommended carriage to board, 1-indexed from the front of the vehicle. May represent a logical position rather than exact carriage number. Must be less than or equal to `carriage_count`. | +| `carriage_count` | Positive integer | **Required** | Number of carriage positions in this configuration. May represent logical divisions (e.g., 3 for front/middle/back) rather than actual carriage count. | +| `facility_type` | Enum | Optional | Type of facility available close to the recommended carriage. Valid options are:

`elevator` - Elevator access.
`escalator` - Escalator access.
`stairs` - Stair access.

May be empty if the destination is another platform or general exit. | ### levels.txt From c334a5a799aaf64083a159326f04f849b6f2c0e3 Mon Sep 17 00:00:00 2001 From: Guillaume Campagna Date: Mon, 23 Feb 2026 15:29:04 -0500 Subject: [PATCH 05/13] Update spec --- gtfs/spec/en/reference.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md index 406421bf..988cab0c 100644 --- a/gtfs/spec/en/reference.md +++ b/gtfs/spec/en/reference.md @@ -762,7 +762,7 @@ Defines which side of the platform the front carriage stops at. This information | Field Name | Type | Presence | Description | | ------ | ------ | ------ | ------ | | `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the platform. Must reference a stop with `location_type=0`. | -| `front_car_position` | Enum | **Required** | Platform side where the front carriage (carriage 1) stops, from the perspective of a passenger facing the track. Valid options are:

`left` - Front carriage stops on the left side of the platform.
`right` - Front carriage stops on the right side of the platform. | +| `front_car_position` | Enum | **Required** | Platform side where the front carriage (carriage 0) stops, from the perspective of a passenger facing the track. Valid options are:

`left` - Front carriage stops on the left side of the platform.
`right` - Front carriage stops on the right side of the platform. | ### carriage_positions.txt @@ -774,13 +774,13 @@ Defines optimal carriage positioning for transfers and platform exit access. Ena While [pathways.txt](#pathwaystxt) handles navigation within stations, it does not address where to stand on the platform before boarding. This file complements pathways by providing carriage-level boarding recommendations. -Producers MAY use logical carriage divisions when exact carriage positions are unavailable. For example, `carriage_count=3` with `recommended_carriage=1` indicates "board near the front" regardless of actual vehicle length. +Producers MAY use logical carriage divisions when exact carriage positions are unavailable. For example, `carriage_count=3` with `recommended_carriage=0` indicates "board near the front" regardless of actual vehicle length. | Field Name | Type | Presence | Description | | ------ | ------ | ------ | ------ | | `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the arrival platform. Must reference a stop with `location_type=0`. | | `to_stop_id` | Foreign ID referencing `stops.stop_id` | Optional | Identifies a specific destination: a transfer platform, station entrance, or exit. Must reference a stop with `location_type=0` or `location_type=2`. When empty, the recommendation applies as a general default for the station. When provided, it gives a destination-specific recommendation that takes priority over the general default. | -| `recommended_carriage` | Positive integer | **Required** | The recommended carriage to board, 1-indexed from the front of the vehicle. May represent a logical position rather than exact carriage number. Must be less than or equal to `carriage_count`. | +| `recommended_carriage` | Non-negative integer | **Required** | The recommended carriage to board, 0-indexed from the front of the vehicle. May represent a logical position rather than exact carriage number. Must be less than `carriage_count`. | | `carriage_count` | Positive integer | **Required** | Number of carriage positions in this configuration. May represent logical divisions (e.g., 3 for front/middle/back) rather than actual carriage count. | | `facility_type` | Enum | Optional | Type of facility available close to the recommended carriage. Valid options are:

`elevator` - Elevator access.
`escalator` - Escalator access.
`stairs` - Stair access.

May be empty if the destination is another platform or general exit. | From 0ca06b9b68bdab3023a8c9c2fbbd69ae1c0995f9 Mon Sep 17 00:00:00 2001 From: Guillaume Campagna Date: Fri, 24 Jul 2026 22:33:12 -0400 Subject: [PATCH 06/13] Update --- gtfs/spec/en/reference.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md index 988cab0c..bc82c03d 100644 --- a/gtfs/spec/en/reference.md +++ b/gtfs/spec/en/reference.md @@ -755,20 +755,22 @@ Pathways are intended to exhaustively define the internal access graph of a stat File: **Optional** -Primary key (`stop_id`) +Primary key (`stop_id`, `route_id`, `direction_id`) -Defines which side of the platform the front carriage stops at. This information is used alongside [carriage_positions.txt](#carriage_positionstxt) to determine boarding recommendations. When the departure and arrival stations have different front car directions, trip planners can mirror the recommended carriage accordingly. +Defines which side of the platform the front carriage stops at. This platform side applies by default to all trips of any routes and directions, unless `route_id` and/or `direction_id` are provided. Both fields allow modeling special configurations, e.g. a platform located on a bidirectional single-track section. This information is used alongside [carriage_positions.txt](#carriage_positionstxt) to determine boarding recommendations. When the departure and arrival stations have different front car directions, trip planners can mirror the recommended carriage accordingly. | Field Name | Type | Presence | Description | | ------ | ------ | ------ | ------ | | `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the platform. Must reference a stop with `location_type=0`. | -| `front_car_position` | Enum | **Required** | Platform side where the front carriage (carriage 0) stops, from the perspective of a passenger facing the track. Valid options are:

`left` - Front carriage stops on the left side of the platform.
`right` - Front carriage stops on the right side of the platform. | +| `front_car_position` | Enum | **Required** | Platform side where the front carriage (carriage 0) stops at, from the perspective of a passenger facing the track. Valid options are:

`left` - Front carriage stops on the left side of the platform.
`right` - Front carriage stops on the right side of the platform. | +| `route_id` | Foreign ID referencing `routes.route_id` | Optional | Specifies per route which side of the platform the front car stops at. Can be defined in combination with `direction_id`. | +| `direction_id` | Enum | Optional | Specifies per trip direction which side of the platform the front car stops at. Can be defined in combination with `route_id`. Valid options are:

`0` - Travel in one direction (e.g., outbound travel).
`1` - Travel in the opposite direction (e.g., inbound travel). | ### carriage_positions.txt File: **Optional** -Primary key (`stop_id`, `to_stop_id`, `facility_type`) +Primary key (`stop_id`, `to_stop_id`, `facility_type`, `carriage_count`) Defines optimal carriage positioning for transfers and platform exit access. Enables trip planners to recommend which carriage passengers should board to minimize walking time at their destination. From 01b9ecff62f7ee02bc5d337692e49508518c1868 Mon Sep 17 00:00:00 2001 From: Guillaume Campagna Date: Fri, 24 Jul 2026 22:51:26 -0400 Subject: [PATCH 07/13] Add carriage mirroring formula to station_directions.txt Spell out how trip planners translate a carriage_positions.txt recommendation when the departure and arrival platforms have opposite front_car_position values, so the off-by-one isn't left to consumers to re-derive. Claude-Session: https://claude.ai/code/session_014myjtAsSUXHGTssztGHLtD --- gtfs/spec/en/reference.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md index c189f8fc..a3a21279 100644 --- a/gtfs/spec/en/reference.md +++ b/gtfs/spec/en/reference.md @@ -766,7 +766,9 @@ File: **Optional** Primary key (`stop_id`, `route_id`, `direction_id`) -Defines which side of the platform the front carriage stops at. This platform side applies by default to all trips of any routes and directions, unless `route_id` and/or `direction_id` are provided. Both fields allow modeling special configurations, e.g. a platform located on a bidirectional single-track section. This information is used alongside [carriage_positions.txt](#carriage_positionstxt) to determine boarding recommendations. When the departure and arrival stations have different front car directions, trip planners can mirror the recommended carriage accordingly. +Defines which side of the platform the front carriage stops at. This platform side applies by default to all trips of any routes and directions, unless `route_id` and/or `direction_id` are provided. Both fields allow modeling special configurations, e.g. a platform located on a bidirectional single-track section. This information is used alongside [carriage_positions.txt](#carriage_positionstxt) to determine boarding recommendations. + +Recommendations in [carriage_positions.txt](#carriage_positionstxt) are relative to the front of the train at the arrival platform, but passengers board at the departure platform. When the two platforms have opposite `front_car_position` values, trip planners mirror the recommendation with `mirrored_carriage = carriage_count - recommended_carriage - 1`. For example, a `recommended_carriage=1` out of `carriage_count=8` at the arrival platform becomes carriage 6 at the departure platform: the same physical position, counted from the other end. | Field Name | Type | Presence | Description | | ------ | ------ | ------ | ------ | From b989c9494ffb42eaf4c96d6e333de1cf0d6af3a3 Mon Sep 17 00:00:00 2001 From: Guillaume Campagna Date: Fri, 24 Jul 2026 23:28:48 -0400 Subject: [PATCH 08/13] Align carriage positioning with spec conventions - Use integer enums for front_car_position and facility_type; facility_type reuses the pathway_mode values instead of introducing a second numbering for stairs, escalator and elevator - Accept platforms with an empty location_type, as pathways.txt does, and spell out which location types are forbidden - Make station_directions.txt Conditionally Required when carriage_positions.txt is provided, since a recommendation cannot be interpreted without knowing platform orientation - State how route_id and direction_id records take priority over the default, and which record wins when several match a trip Claude-Session: https://claude.ai/code/session_014myjtAsSUXHGTssztGHLtD --- gtfs/spec/en/reference.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md index a3a21279..325ebdd0 100644 --- a/gtfs/spec/en/reference.md +++ b/gtfs/spec/en/reference.md @@ -141,7 +141,7 @@ This specification defines the following files: | [frequencies.txt](#frequenciestxt) | Optional | Headway (time between trips) for headway-based service or a compressed representation of fixed-schedule service. | | [transfers.txt](#transferstxt) | Optional | Rules for making connections at transfer points between routes. | | [pathways.txt](#pathwaystxt) | Optional | Pathways linking together locations within stations. | -| [station_directions.txt](#station_directionstxt) | Optional | Platform direction of the front carriage at each stop. | +| [station_directions.txt](#station_directionstxt) | **Conditionally Required** | Platform direction of the front carriage at each stop.

Conditionally Required:
- **Required** when [carriage_positions.txt](#carriage_positionstxt) is provided.
- Optional otherwise. | | [carriage_positions.txt](#carriage_positionstxt) | Optional | Optimal carriage positioning for transfers and platform exits. | | [levels.txt](#levelstxt) | **Conditionally Required** | Levels within stations.

Conditionally Required:
- **Required** when describing pathways with elevators (`pathway_mode=5`).
- Optional otherwise. | | [location_groups.txt](#location_groupstxt) | Optional | A group of stops that together indicate locations where a rider may request pickup or drop off. | @@ -762,18 +762,20 @@ Pathways are intended to exhaustively define the internal access graph of a stat ### station_directions.txt -File: **Optional** +File: **Conditionally Required** Primary key (`stop_id`, `route_id`, `direction_id`) -Defines which side of the platform the front carriage stops at. This platform side applies by default to all trips of any routes and directions, unless `route_id` and/or `direction_id` are provided. Both fields allow modeling special configurations, e.g. a platform located on a bidirectional single-track section. This information is used alongside [carriage_positions.txt](#carriage_positionstxt) to determine boarding recommendations. +Defines which side of the platform the front carriage stops at. This information is used alongside [carriage_positions.txt](#carriage_positionstxt) to determine boarding recommendations. + +A record with empty `route_id` and `direction_id` defines the platform side for all trips serving the platform. Records that specify `route_id` and/or `direction_id` take priority over that default for the trips they match, which allows modeling special configurations, e.g. a platform located on a bidirectional single-track section. When several records match a trip, the most specific one applies, in the following order: (`route_id`, `direction_id`), then `route_id`, then `direction_id`, then the default record. -Recommendations in [carriage_positions.txt](#carriage_positionstxt) are relative to the front of the train at the arrival platform, but passengers board at the departure platform. When the two platforms have opposite `front_car_position` values, trip planners mirror the recommendation with `mirrored_carriage = carriage_count - recommended_carriage - 1`. For example, a `recommended_carriage=1` out of `carriage_count=8` at the arrival platform becomes carriage 6 at the departure platform: the same physical position, counted from the other end. +Recommendations in [carriage_positions.txt](#carriage_positionstxt) are relative to the front of the train at the arrival platform, but passengers board at the departure platform. When the two platforms have opposite `front_car_position` values, trip planners mirror the recommendation with `mirrored_carriage = carriage_count - recommended_carriage - 1`. For example, a `recommended_carriage=1` out of `carriage_count=8` at the arrival platform becomes carriage 6 at the departure platform: the same physical position, counted from the other end. Data consumers should only apply a recommendation when `front_car_position` is known for both the departure and the arrival platform. | Field Name | Type | Presence | Description | | ------ | ------ | ------ | ------ | -| `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the platform. Must reference a stop with `location_type=0`. | -| `front_car_position` | Enum | **Required** | Platform side where the front carriage (carriage 0) stops at, from the perspective of a passenger facing the track. Valid options are:

`left` - Front carriage stops on the left side of the platform.
`right` - Front carriage stops on the right side of the platform. | +| `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the platform.

Must contain a `stop_id` that identifies a platform (`location_type=0` or empty).

Values for `stop_id` that identify stations (`location_type=1`), entrances/exits (`location_type=2`), generic nodes (`location_type=3`) or boarding areas (`location_type=4`) are forbidden. | +| `front_car_position` | Enum | **Required** | Platform side where the front carriage (carriage 0) stops at, from the perspective of a passenger facing the track. Valid options are:

`0` - Front carriage stops on the left side of the platform.
`1` - Front carriage stops on the right side of the platform. | | `route_id` | Foreign ID referencing `routes.route_id` | Optional | Specifies per route which side of the platform the front car stops at. Can be defined in combination with `direction_id`. | | `direction_id` | Enum | Optional | Specifies per trip direction which side of the platform the front car stops at. Can be defined in combination with `route_id`. Valid options are:

`0` - Travel in one direction (e.g., outbound travel).
`1` - Travel in the opposite direction (e.g., inbound travel). | @@ -791,11 +793,11 @@ Producers MAY use logical carriage divisions when exact carriage positions are u | Field Name | Type | Presence | Description | | ------ | ------ | ------ | ------ | -| `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the arrival platform. Must reference a stop with `location_type=0`. | -| `to_stop_id` | Foreign ID referencing `stops.stop_id` | Optional | Identifies a specific destination: a transfer platform, station entrance, or exit. Must reference a stop with `location_type=0` or `location_type=2`. When empty, the recommendation applies as a general default for the station. When provided, it gives a destination-specific recommendation that takes priority over the general default. | +| `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the arrival platform.

Must contain a `stop_id` that identifies a platform (`location_type=0` or empty).

Values for `stop_id` that identify stations (`location_type=1`), entrances/exits (`location_type=2`), generic nodes (`location_type=3`) or boarding areas (`location_type=4`) are forbidden. | +| `to_stop_id` | Foreign ID referencing `stops.stop_id` | Optional | Identifies a specific destination, either a transfer platform or a station entrance/exit.

Must contain a `stop_id` that identifies a platform (`location_type=0` or empty) or an entrance/exit (`location_type=2`). Values for `stop_id` that identify stations (`location_type=1`), generic nodes (`location_type=3`) or boarding areas (`location_type=4`) are forbidden.

When empty, the recommendation applies as a general default for the station. When provided, it gives a destination-specific recommendation that takes priority over the general default. | | `recommended_carriage` | Non-negative integer | **Required** | The recommended carriage to board, 0-indexed from the front of the vehicle. May represent a logical position rather than exact carriage number. Must be less than `carriage_count`. | | `carriage_count` | Positive integer | **Required** | Number of carriage positions in this configuration. May represent logical divisions (e.g., 3 for front/middle/back) rather than actual carriage count. | -| `facility_type` | Enum | Optional | Type of facility available close to the recommended carriage. Valid options are:

`elevator` - Elevator access.
`escalator` - Escalator access.
`stairs` - Stair access.

May be empty if the destination is another platform or general exit. | +| `facility_type` | Enum | Optional | Type of facility available close to the recommended carriage. Valid options are a subset of [pathways.txt](#pathwaystxt) `pathway_mode`:

`2` - Stairs.
`4` - Escalator.
`5` - Elevator.

May be empty when the recommendation is not tied to a specific facility. | ### levels.txt From 9d88a6aa83c02bf75004f82b550b8576f10c1db4 Mon Sep 17 00:00:00 2001 From: Guillaume Campagna Date: Fri, 24 Jul 2026 23:44:22 -0400 Subject: [PATCH 09/13] Number carriages from 1 as in CarriageDetails.carriage_sequence Consumers combining a boarding recommendation with real-time per-carriage occupancy would otherwise have to translate between two numbering schemes for the same concept. Mirroring becomes carriage_count - recommended_carriage + 1. Claude-Session: https://claude.ai/code/session_014myjtAsSUXHGTssztGHLtD --- gtfs/spec/en/reference.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md index 325ebdd0..780d6308 100644 --- a/gtfs/spec/en/reference.md +++ b/gtfs/spec/en/reference.md @@ -770,12 +770,12 @@ Defines which side of the platform the front carriage stops at. This information A record with empty `route_id` and `direction_id` defines the platform side for all trips serving the platform. Records that specify `route_id` and/or `direction_id` take priority over that default for the trips they match, which allows modeling special configurations, e.g. a platform located on a bidirectional single-track section. When several records match a trip, the most specific one applies, in the following order: (`route_id`, `direction_id`), then `route_id`, then `direction_id`, then the default record. -Recommendations in [carriage_positions.txt](#carriage_positionstxt) are relative to the front of the train at the arrival platform, but passengers board at the departure platform. When the two platforms have opposite `front_car_position` values, trip planners mirror the recommendation with `mirrored_carriage = carriage_count - recommended_carriage - 1`. For example, a `recommended_carriage=1` out of `carriage_count=8` at the arrival platform becomes carriage 6 at the departure platform: the same physical position, counted from the other end. Data consumers should only apply a recommendation when `front_car_position` is known for both the departure and the arrival platform. +Recommendations in [carriage_positions.txt](#carriage_positionstxt) are relative to the front of the train at the arrival platform, but passengers board at the departure platform. When the two platforms have opposite `front_car_position` values, trip planners mirror the recommendation with `mirrored_carriage = carriage_count - recommended_carriage + 1`. For example, a `recommended_carriage=2` out of `carriage_count=8` at the arrival platform becomes carriage 7 at the departure platform: the same physical position, counted from the other end. Data consumers should only apply a recommendation when `front_car_position` is known for both the departure and the arrival platform. | Field Name | Type | Presence | Description | | ------ | ------ | ------ | ------ | | `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the platform.

Must contain a `stop_id` that identifies a platform (`location_type=0` or empty).

Values for `stop_id` that identify stations (`location_type=1`), entrances/exits (`location_type=2`), generic nodes (`location_type=3`) or boarding areas (`location_type=4`) are forbidden. | -| `front_car_position` | Enum | **Required** | Platform side where the front carriage (carriage 0) stops at, from the perspective of a passenger facing the track. Valid options are:

`0` - Front carriage stops on the left side of the platform.
`1` - Front carriage stops on the right side of the platform. | +| `front_car_position` | Enum | **Required** | Platform side where the front carriage stops at, from the perspective of a passenger facing the track. Valid options are:

`0` - Front carriage stops on the left side of the platform.
`1` - Front carriage stops on the right side of the platform. | | `route_id` | Foreign ID referencing `routes.route_id` | Optional | Specifies per route which side of the platform the front car stops at. Can be defined in combination with `direction_id`. | | `direction_id` | Enum | Optional | Specifies per trip direction which side of the platform the front car stops at. Can be defined in combination with `route_id`. Valid options are:

`0` - Travel in one direction (e.g., outbound travel).
`1` - Travel in the opposite direction (e.g., inbound travel). | @@ -789,13 +789,13 @@ Defines optimal carriage positioning for transfers and platform exit access. Ena While [pathways.txt](#pathwaystxt) handles navigation within stations, it does not address where to stand on the platform before boarding. This file complements pathways by providing carriage-level boarding recommendations. -Producers MAY use logical carriage divisions when exact carriage positions are unavailable. For example, `carriage_count=3` with `recommended_carriage=0` indicates "board near the front" regardless of actual vehicle length. +Producers MAY use logical carriage divisions when exact carriage positions are unavailable. For example, `carriage_count=3` with `recommended_carriage=1` indicates "board near the front" regardless of actual vehicle length. | Field Name | Type | Presence | Description | | ------ | ------ | ------ | ------ | | `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the arrival platform.

Must contain a `stop_id` that identifies a platform (`location_type=0` or empty).

Values for `stop_id` that identify stations (`location_type=1`), entrances/exits (`location_type=2`), generic nodes (`location_type=3`) or boarding areas (`location_type=4`) are forbidden. | | `to_stop_id` | Foreign ID referencing `stops.stop_id` | Optional | Identifies a specific destination, either a transfer platform or a station entrance/exit.

Must contain a `stop_id` that identifies a platform (`location_type=0` or empty) or an entrance/exit (`location_type=2`). Values for `stop_id` that identify stations (`location_type=1`), generic nodes (`location_type=3`) or boarding areas (`location_type=4`) are forbidden.

When empty, the recommendation applies as a general default for the station. When provided, it gives a destination-specific recommendation that takes priority over the general default. | -| `recommended_carriage` | Non-negative integer | **Required** | The recommended carriage to board, 0-indexed from the front of the vehicle. May represent a logical position rather than exact carriage number. Must be less than `carriage_count`. | +| `recommended_carriage` | Positive integer | **Required** | The recommended carriage to board, numbered from the first carriage in the direction of travel, which has a value of `1`, as in GTFS-realtime `CarriageDetails.carriage_sequence`. May represent a logical position rather than an exact carriage number. Must be less than or equal to `carriage_count`. | | `carriage_count` | Positive integer | **Required** | Number of carriage positions in this configuration. May represent logical divisions (e.g., 3 for front/middle/back) rather than actual carriage count. | | `facility_type` | Enum | Optional | Type of facility available close to the recommended carriage. Valid options are a subset of [pathways.txt](#pathwaystxt) `pathway_mode`:

`2` - Stairs.
`4` - Escalator.
`5` - Elevator.

May be empty when the recommendation is not tied to a specific facility. | From 37c59fd3a2c37ee3e931291a95daed51a957f9ed Mon Sep 17 00:00:00 2001 From: Guillaume Campagna Date: Fri, 24 Jul 2026 23:56:27 -0400 Subject: [PATCH 10/13] Point direction_id at trips.txt instead of restating its values Claude-Session: https://claude.ai/code/session_014myjtAsSUXHGTssztGHLtD --- gtfs/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md index 780d6308..3e56096b 100644 --- a/gtfs/spec/en/reference.md +++ b/gtfs/spec/en/reference.md @@ -777,7 +777,7 @@ Recommendations in [carriage_positions.txt](#carriage_positionstxt) are relative | `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the platform.

Must contain a `stop_id` that identifies a platform (`location_type=0` or empty).

Values for `stop_id` that identify stations (`location_type=1`), entrances/exits (`location_type=2`), generic nodes (`location_type=3`) or boarding areas (`location_type=4`) are forbidden. | | `front_car_position` | Enum | **Required** | Platform side where the front carriage stops at, from the perspective of a passenger facing the track. Valid options are:

`0` - Front carriage stops on the left side of the platform.
`1` - Front carriage stops on the right side of the platform. | | `route_id` | Foreign ID referencing `routes.route_id` | Optional | Specifies per route which side of the platform the front car stops at. Can be defined in combination with `direction_id`. | -| `direction_id` | Enum | Optional | Specifies per trip direction which side of the platform the front car stops at. Can be defined in combination with `route_id`. Valid options are:

`0` - Travel in one direction (e.g., outbound travel).
`1` - Travel in the opposite direction (e.g., inbound travel). | +| `direction_id` | Enum | Optional | Specifies per trip direction which side of the platform the front car stops at. Can be defined in combination with `route_id`.

Values are the same as [trips.txt](#tripstxt) `direction_id`. | ### carriage_positions.txt From b79d74bc7ddbf1cd0a853d4d0106b6b9628989de Mon Sep 17 00:00:00 2001 From: Guillaume Campagna Date: Fri, 24 Jul 2026 23:58:57 -0400 Subject: [PATCH 11/13] Clarify how to read stop_id and to_stop_id together Claude-Session: https://claude.ai/code/session_014myjtAsSUXHGTssztGHLtD --- gtfs/spec/en/reference.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md index 3e56096b..f4aa558b 100644 --- a/gtfs/spec/en/reference.md +++ b/gtfs/spec/en/reference.md @@ -787,6 +787,8 @@ Primary key (`stop_id`, `to_stop_id`, `facility_type`, `carriage_count`) Defines optimal carriage positioning for transfers and platform exit access. Enables trip planners to recommend which carriage passengers should board to minimize walking time at their destination. +A record describes the moment a rider steps off a train: `stop_id` is the platform where the rider alights and `to_stop_id` is where the rider continues to, while the recommendation itself is applied earlier, when the rider boards. + While [pathways.txt](#pathwaystxt) handles navigation within stations, it does not address where to stand on the platform before boarding. This file complements pathways by providing carriage-level boarding recommendations. Producers MAY use logical carriage divisions when exact carriage positions are unavailable. For example, `carriage_count=3` with `recommended_carriage=1` indicates "board near the front" regardless of actual vehicle length. From abfe0856b08f31e7472781b88ddaafa4d7d0089b Mon Sep 17 00:00:00 2001 From: Guillaume Campagna Date: Sat, 25 Jul 2026 00:01:18 -0400 Subject: [PATCH 12/13] Spell out the two kinds of to_stop_id destination Claude-Session: https://claude.ai/code/session_014myjtAsSUXHGTssztGHLtD --- gtfs/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md index f4aa558b..f4b08026 100644 --- a/gtfs/spec/en/reference.md +++ b/gtfs/spec/en/reference.md @@ -787,7 +787,7 @@ Primary key (`stop_id`, `to_stop_id`, `facility_type`, `carriage_count`) Defines optimal carriage positioning for transfers and platform exit access. Enables trip planners to recommend which carriage passengers should board to minimize walking time at their destination. -A record describes the moment a rider steps off a train: `stop_id` is the platform where the rider alights and `to_stop_id` is where the rider continues to, while the recommendation itself is applied earlier, when the rider boards. +A record describes the moment a rider steps off a train: `stop_id` is the platform where the rider alights, and `to_stop_id` is where the rider continues to, either another platform when transferring or an entrance/exit when leaving the station. The recommendation itself is applied earlier, when the rider boards. While [pathways.txt](#pathwaystxt) handles navigation within stations, it does not address where to stand on the platform before boarding. This file complements pathways by providing carriage-level boarding recommendations. From cfa951b427b4c275204b7ffb3fe9dd969531c46b Mon Sep 17 00:00:00 2001 From: Guillaume Campagna Date: Sat, 25 Jul 2026 00:02:15 -0400 Subject: [PATCH 13/13] Recommend that to_stop_id stays within the same station Kept as a should so that connected platforms modeled as separate stations, such as transfers between operators, can still be described. Claude-Session: https://claude.ai/code/session_014myjtAsSUXHGTssztGHLtD --- gtfs/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md index f4b08026..ae966c7a 100644 --- a/gtfs/spec/en/reference.md +++ b/gtfs/spec/en/reference.md @@ -796,7 +796,7 @@ Producers MAY use logical carriage divisions when exact carriage positions are u | Field Name | Type | Presence | Description | | ------ | ------ | ------ | ------ | | `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the arrival platform.

Must contain a `stop_id` that identifies a platform (`location_type=0` or empty).

Values for `stop_id` that identify stations (`location_type=1`), entrances/exits (`location_type=2`), generic nodes (`location_type=3`) or boarding areas (`location_type=4`) are forbidden. | -| `to_stop_id` | Foreign ID referencing `stops.stop_id` | Optional | Identifies a specific destination, either a transfer platform or a station entrance/exit.

Must contain a `stop_id` that identifies a platform (`location_type=0` or empty) or an entrance/exit (`location_type=2`). Values for `stop_id` that identify stations (`location_type=1`), generic nodes (`location_type=3`) or boarding areas (`location_type=4`) are forbidden.

When empty, the recommendation applies as a general default for the station. When provided, it gives a destination-specific recommendation that takes priority over the general default. | +| `to_stop_id` | Foreign ID referencing `stops.stop_id` | Optional | Identifies a specific destination, either a transfer platform or a station entrance/exit.

Must contain a `stop_id` that identifies a platform (`location_type=0` or empty) or an entrance/exit (`location_type=2`). Values for `stop_id` that identify stations (`location_type=1`), generic nodes (`location_type=3`) or boarding areas (`location_type=4`) are forbidden.

Should belong to the same station (`stops.parent_station`) as `stop_id`, as the recommendation describes walking within a station, but may reference a location in another station when physically connected platforms are modeled separately.

When empty, the recommendation applies as a general default for the station. When provided, it gives a destination-specific recommendation that takes priority over the general default. | | `recommended_carriage` | Positive integer | **Required** | The recommended carriage to board, numbered from the first carriage in the direction of travel, which has a value of `1`, as in GTFS-realtime `CarriageDetails.carriage_sequence`. May represent a logical position rather than an exact carriage number. Must be less than or equal to `carriage_count`. | | `carriage_count` | Positive integer | **Required** | Number of carriage positions in this configuration. May represent logical divisions (e.g., 3 for front/middle/back) rather than actual carriage count. | | `facility_type` | Enum | Optional | Type of facility available close to the recommended carriage. Valid options are a subset of [pathways.txt](#pathwaystxt) `pathway_mode`:

`2` - Stairs.
`4` - Escalator.
`5` - Elevator.

May be empty when the recommendation is not tied to a specific facility. |