Skip to content

[Fares V2] Support for filtering fare leg rules by number of stops (hop count) #7141

@vinnykova

Description

@vinnykova

Title: [Fares V2] Support for filtering fare leg rules by number of stops (hop count)

Introduction / Context
We are currently evaluating OTP for our use case and have identified a functional gap in the Fares V2 area. We are looking for feedback: Does this feature fit into the roadmap? How should the configuration (GTFS Extension vs. standard field) ideally be handled?

Is your feature request related to a problem? Please describe.
Yes. Many public transport agencies (particularly in the DACH region) offer "short-haul" tickets (e.g., "Kurzstrecke"). These tickets are often defined by the number of stops/stations traveled (e.g., "valid for up to 3 stops on the tram" or "up to 5 stops on the bus"), rather than by geographic distance.

Currently, OTP's implementation of GTFS Fares V2 allows filtering fare_leg_rules.txt by max_distance, but there is no native support for filtering by the number of stops (hop count). Using max_distance as a proxy for stop count is inaccurate because the distance between stations varies significantly. This leads to edge cases where short-haul tickets are either wrongly denied (long distance between few stops) or wrongly granted (short distance between many stops).

Goal / high level use-case
The goal is to allow OTP to accurately match fare products based on the specific number of stops traveled in a leg.

Use Case:
A user searches for a connection involving a short tram ride (e.g., 3 stations). The system should check the number of stops for this leg and, if it falls within the configured limit (e.g., max_stops=3), apply the cheaper "Short Haul" fare product defined in fare_leg_rules.txt.

Describe the solution you'd like
We would like to extend the Fares V2 matching logic in OTP to support filtering by stop count.

  1. Extend the internal FareLegRule model to include a stop count limit (e.g., mapped from a GTFS extension field like x_max_stops in fare_leg_rules.txt or a similar mechanism).
  2. Update the FareLegRuleMatcher to count the stops of the leg being evaluated and compare them against this limit.

Describe alternatives you've considered
We have considered the following alternatives, but they are not ideal:

  1. Filtering in Middleware: Calculating fares in OTP based on zones and then filtering out invalid short-haul tickets in a middleware layer by counting stops there. This splits the business logic and increases complexity.
  2. Filtering in Frontend: Sending all possible tickets to the client and letting the frontend filter based on stop count. This is insecure and exposes incorrect data in the API response.
  3. Using max_distance: As described above, distance is an unreliable proxy for stop count in our network topology.

Additional context
We are currently evaluating OTP for our use case. We would appreciate guidance from the maintainers on the preferred implementation approach and how this aligns with the Fares V2 roadmap.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions