Skip to content

feat: warn when trip_headsign matches intermediate stop name#2139

Merged
davidgamez merged 7 commits intoMobilityData:masterfrom
PatrickSteil:master
Apr 28, 2026
Merged

feat: warn when trip_headsign matches intermediate stop name#2139
davidgamez merged 7 commits intoMobilityData:masterfrom
PatrickSteil:master

Conversation

@PatrickSteil
Copy link
Copy Markdown
Contributor

Adds a new validation rule TripHeadsignValidator that warns when a trip's trip_headsign matches the stop_name of an intermediate stop (i.e., any stop that is not the last stop of the trip). This can cause confusion for passengers boarding after that stop, as the headsign suggests the vehicle is heading somewhere it has already passed.
The notice TripHeadsignMatchesIntermediateStopNotice is emitted as a WARNING and includes:

  • the offending trip_id and its row number in trips.txt
  • the trip_headsign value
  • the stop_id and stop_sequence of the intermediate stop matching the trip_headsign
  • the stop_id of the actual last stop of the trip

NoticeFieldsTest has been updated to register a new notice field name introduced: tripHeadsign.

Note that if a trip visits the last stop multiple times, then no warning is shown.

The following screenshot shows a real-world example of the official Swiss GTFS feed, where a trip passed through St. Gallen, and continues to Winterthur. But the trip_headsign shows St. Gallen.

Screenshot 2026-03-28 at 14 20 28

@welcome
Copy link
Copy Markdown

welcome Bot commented Mar 28, 2026

Thanks for opening this pull request! You're awesome. We use semantic commit messages to streamline the release process. Before your pull request can be merged, you should update your pull request title to start with a semantic prefix. Examples of titles with semantic prefixes:

  • fix: Bug with ssl network connections + Java module permissions.
  • feat: Initial support for multiple @PrimaryKey annotations.
  • docs: update RELEASE.md with new process
    To get this PR to the finish line, please do the following:
  • Read our Contribution Guidelines
  • Follow Google Java style coding standards
  • Include tests when adding/changing behavior
  • Include screenshots

@PatrickSteil
Copy link
Copy Markdown
Contributor Author

In this PR patrickbr/gtfstidy#41, i posted the same example but with a screenshot of the trip's route, as well as implementing a fix by overwriting the stop_headsign.

@emmambd
Copy link
Copy Markdown
Contributor

emmambd commented Apr 24, 2026

Thanks @PatrickSteil for this great rule addition!

There are some cases where the trip headsign changes mid-trip. In this situation, the best practices recommend that feeds set trip.headsign to an intermediate stop and then override it using stop_times.stop_headsign for the later portion.

Screenshot 2026-04-22 at 1 24 31 PM

Due to this case, we'd like to proceed with downgrading this rule from a WARNING to INFO severity, since there are some cases where the trip_headsign matching an intermediate stop name is valid behavior. cc @tzujenchanmbd @skalexch

@PatrickSteil
Copy link
Copy Markdown
Contributor Author

Thank you for your comment, I changed the WARNING to INFO. I tested i locally on the Swiss Instance, and it is now shown as INFO.
Bildschirmfoto vom 2026-04-24 18-15-23

@davidgamez davidgamez self-requested a review April 27, 2026 20:38
Copy link
Copy Markdown
Member

@davidgamez davidgamez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great contribution! I just added a comment regarding the method's performance easy to fix.
Thanks!

}

// Sort by stop_sequence to find the true last stop
List<GtfsStopTime> sorted =
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stopTimes list is already sorted by sequence. This is specified in the schema, link. In your local generated code GtfsStopTimeTableContainer, you can find the generated method with the following comment:

  /**
   * @return List of org.mobilitydata.gtfsvalidator.table.GtfsStopTime sorted by stop_sequence
   */

Even though the list is already sorted, and that helps the sorting algorithm, stop times tend to be a large file; having a stream and sorting will impact performance for larger feeds.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize this may not be well-documented for developers, and I apologize for that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! Yes, I was not sure whether i could assume the stop times to be sorted :) I am going to rewrite this

@davidgamez davidgamez merged commit 2976658 into MobilityData:master Apr 28, 2026
103 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants