Skip to content

Rjf/gbfs - #162

Merged
robfitzgerald merged 47 commits into
mainfrom
rjf/gbfs
Aug 27, 2026
Merged

robfitzgerald merged 47 commits into
mainfrom
rjf/gbfs

Conversation

@robfitzgerald

@robfitzgerald robfitzgerald commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

this PR includes the change set required to support GBFS-mode search. a GBFS trip has two components, the Constraint step and Traversal step, which are used along with a few default models to implement the behaviors.

Import

a single and batch download/import CLI command will import from either a single URL or a manifest CSV with many URLs, the latter command looks like this:

% RUST_LOG=info bambam-gbfs batch-download --csv-file systems.csv --csv-column "Auto-Discovery URL" --entry-point gbfs -o network --delay 2 --parallelism 6

where systems.csv is the MobilityData GBFS Systems list CSV file.

Run

Here is an example BAMBAM.toml config file with walk and GBFS mode trips. To reuse, ensure the file paths are correct, and both the LODES state FIPS geoid(s) and overture bbox argument match the study region. the overture-to-mep.csv file maps overture POI to MEP categories.

in the config, both constraint model and traversal model expect the same files:

pub struct GbfsConstraintConfig {
    /// output of bambam-gbfs CLI import process, contains a record of the
    /// identifier, optional start/end times for service, and traversal ruleset
    /// for default vehicles (trips without a VehicleTripId).
    ///
    /// see [crate::model::gbfs::GbfsZoneRecord]
    pub zone_record_input_file: String,
    /// output of bambam-gbfs CLI import process, contains zonal geometries
    /// with matching indices to the zones input file.
    pub zone_geometry_input_file: String,
    /// fully-qualified identifiers for each record with matching index to zone + geometry files.
    pub zone_ids_input_file: String,
}

the traversal config also expects a default travel speed, similar to the way we model bike mode, except for GBFS, it can be limited to the maximum_speed_kph of a zone:

pub struct GbfsTraversalConfig {
    /// above files...
    /// speed to use for GBFS trips. can be limited by zone-specific max speeds.
    pub default_speed: DefaultSpeed,
}

pub struct DefaultSpeed {
    pub speed: f64,
    pub speed_unit: SpeedUnit,
}

at query time, the algorithm expects a start_time as a DateTime in RFC3339 format, which is combined with the active search trip_time to test against any start/end times listed on zones.

Algorithms Implemented

Constraint (validate edge traversal), as a list of predicates:
  - does our position not intersect with any zone? -> FALSE
  - have we NOT boarded a trip and `ride_start_allowed` is FALSE for any intersecting zone? -> FALSE
  - is `ride_through_allowed` FALSE for any intersecting zone? -> FALSE
  - otherwise -> TRUE
# Traversal as pseudocode
def traversal(dst_vertex, state, start_time):
  # invariant: we only traverse after passing the constraint model, so at this point, assume edge is valid
  system_id = get_system_id(state) # -> Option<SystemId>
  zones = rtree.lookup(vertex, current_time, system_id)
  match system_id:
    Some(id) => process_boarded(zones, default_speed, state)
    None => process_unboarded(zones, default_speed, state)

def process_boarded(zones, default_speed, state):
  assert!(zones.len() == 1) # result of rtree lookup with system_id filter  
  zone = zones[0]
  if zone.ride_end_allowed:
    set_gbfs_destination(state)
  let speed = match zone.maximum_speed_kph:
    Some(speed) => min(speed, default_speed)
    None => default_speed
  set_speed(state, speed)

def process_unboarded(zones, default_speed, state):
  zone = find_best_zone(zones)
  set_system_id(state, zone.id)
  process_boarded([zone], default_speed, state)

at current, this PR provides no test coverage for GBFS, as that requires a lot of environment setup, which can follow later (#168).

@robfitzgerald

Copy link
Copy Markdown
Collaborator Author

example output from downloader tool.

% cd rust
% ./target/release/bambam-gbfs download -g "https://chattanooga.publicbikesystem.net/customer/gbfs/v3.0/gbfs.json" -o out
{
  "info": {
    "last_updated": "2026-07-15T21:27:14Z",
    "ttl": 30,
    "version": "3.0",
    "data": {
      "system_id": "bike_chattanooga",
      "languages": [
        "en",
        "fr",
        "nl",
        "es"
      ],
      "name": [
        {
          "text": "bike_chattanooga",
          "language": "en"
        },
        {
          "text": "bike_chattanooga",
          "language": "fr"
        },
        {
          "text": "bike_chattanooga",
          "language": "nl"
        },
        {
          "text": "bike_chattanooga",
          "language": "es"
        }
      ],
      "opening_hours": "Mo-Su,PH 00:00-24:00",
      "feed_contact_email": "mobility-data-client@lyft.com",
      "timezone": "America/New_York"
    }
  },
  "geofence": {
    "last_updated": "2026-07-15T21:27:14Z",
    "ttl": 30,
    "version": "3.0",
    "data": {
      "geofencing_zones": {
        "type": "FeatureCollection",
        "features": []
      },
      "global_rules": []
    }
  }

@robfitzgerald
robfitzgerald marked this pull request as ready for review August 13, 2026 17:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds GBFS-mode routing support, including feed import, geofence lookup, constraint validation, provider selection, and traversal speed handling. GBFS integration tests remain deferred to #168.

Changes:

  • Implements GBFS constraint and traversal models with temporal geofence rules.
  • Adds GBFS 2.2, 2.3, and 3.0 download/import tooling.
  • Replaces earlier GBFS boarding/geofence stubs and registers the new models.

Reviewed changes

Copilot reviewed 61 out of 61 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
rust/Cargo.toml Adds shared GBFS and PyO3 dependencies.
rust/bambam/src/model/traversal/time_delay/time_delay_record.rs Simplifies formatting arguments.
rust/bambam/src/model/input_plugin/population/population_source_config.rs Improves missing-token error text.
rust/bambam/src/model/builders.rs Registers unified GBFS models.
rust/bambam-py/Cargo.toml Uses workspace PyO3 dependency.
rust/bambam-osm/src/model/osm/graph/compass_writer.rs Simplifies formatting argument.
rust/bambam-gbfs/src/model/traversal/mod.rs Exposes the new traversal module.
rust/bambam-gbfs/src/model/traversal/gbfs_traversal/service.rs Builds query-specific traversal models.
rust/bambam-gbfs/src/model/traversal/gbfs_traversal/params.rs Defines traversal query time.
rust/bambam-gbfs/src/model/traversal/gbfs_traversal/model.rs Integrates GBFS traversal with search state.
rust/bambam-gbfs/src/model/traversal/gbfs_traversal/mod.rs Exports traversal components.
rust/bambam-gbfs/src/model/traversal/gbfs_traversal/engine.rs Implements provider selection and speed rules.
rust/bambam-gbfs/src/model/traversal/gbfs_traversal/config.rs Defines traversal file and speed configuration.
rust/bambam-gbfs/src/model/traversal/gbfs_traversal/builder.rs Constructs traversal services.
rust/bambam-gbfs/src/model/traversal/boarding/service.rs Removes obsolete traversal stub.
rust/bambam-gbfs/src/model/traversal/boarding/model.rs Removes obsolete traversal stub.
rust/bambam-gbfs/src/model/traversal/boarding/mod.rs Removes obsolete traversal module.
rust/bambam-gbfs/src/model/traversal/boarding/config.rs Removes obsolete traversal config.
rust/bambam-gbfs/src/model/traversal/boarding/builder.rs Removes obsolete traversal builder.
rust/bambam-gbfs/src/model/mod.rs Exposes GBFS state and feature modules.
rust/bambam-gbfs/src/model/gbfs/state.rs Aggregates intersecting zone rules.
rust/bambam-gbfs/src/model/gbfs/record.rs Defines imported zone records.
rust/bambam-gbfs/src/model/gbfs/ops.rs Adds identifier and time helpers.
rust/bambam-gbfs/src/model/gbfs/mod.rs Exports GBFS lookup types.
rust/bambam-gbfs/src/model/gbfs/lookup.rs Implements spatial and temporal lookup.
rust/bambam-gbfs/src/model/gbfs/lookup_config.rs Defines lookup file configuration.
rust/bambam-gbfs/src/model/feature.rs Defines GBFS search-state features.
rust/bambam-gbfs/src/model/constraint/mod.rs Exposes the unified constraint module.
rust/bambam-gbfs/src/model/constraint/geofence/service.rs Removes obsolete geofence stub.
rust/bambam-gbfs/src/model/constraint/geofence/model.rs Removes obsolete geofence stub.
rust/bambam-gbfs/src/model/constraint/geofence/mod.rs Removes obsolete geofence module.
rust/bambam-gbfs/src/model/constraint/geofence/engine.rs Removes obsolete geofence engine.
rust/bambam-gbfs/src/model/constraint/geofence/config.rs Removes obsolete geofence config.
rust/bambam-gbfs/src/model/constraint/geofence/builder.rs Removes obsolete geofence builder.
rust/bambam-gbfs/src/model/constraint/gbfs_constraint/service.rs Builds query-specific constraint models.
rust/bambam-gbfs/src/model/constraint/gbfs_constraint/params.rs Defines constraint query time.
rust/bambam-gbfs/src/model/constraint/gbfs_constraint/model.rs Connects constraints to search frontiers.
rust/bambam-gbfs/src/model/constraint/gbfs_constraint/mod.rs Exports constraint components.
rust/bambam-gbfs/src/model/constraint/gbfs_constraint/engine.rs Implements GBFS edge eligibility rules.
rust/bambam-gbfs/src/model/constraint/gbfs_constraint/config.rs Defines constraint input configuration.
rust/bambam-gbfs/src/model/constraint/gbfs_constraint/builder.rs Constructs constraint services.
rust/bambam-gbfs/src/model/constraint/boarding/service.rs Removes obsolete boarding stub.
rust/bambam-gbfs/src/model/constraint/boarding/model.rs Removes obsolete boarding stub.
rust/bambam-gbfs/src/model/constraint/boarding/mod.rs Removes obsolete boarding module.
rust/bambam-gbfs/src/model/constraint/boarding/engine.rs Removes obsolete boarding engine.
rust/bambam-gbfs/src/model/constraint/boarding/config.rs Removes obsolete boarding config.
rust/bambam-gbfs/src/model/constraint/boarding/builder.rs Removes obsolete boarding builder.
rust/bambam-gbfs/src/main.rs Runs the CLI asynchronously.
rust/bambam-gbfs/src/app/gbfs_cli.rs Adds versioned download/import commands.
rust/bambam-gbfs/src/app/download/zone_constraints.rs Normalizes and merges GBFS rules.
rust/bambam-gbfs/src/app/download/run.rs Implements batch download and import output.
rust/bambam-gbfs/src/app/download/ops.rs Adds HTTP and CSV helpers.
rust/bambam-gbfs/src/app/download/mod.rs Exposes download/import modules.
rust/bambam-gbfs/src/app/download/gbfs_version.rs Defines supported GBFS versions.
rust/bambam-gbfs/src/app/download/gbfs_v3_0.rs Downloads GBFS 3.0 feeds.
rust/bambam-gbfs/src/app/download/gbfs_v2_3.rs Downloads GBFS 2.3 feeds.
rust/bambam-gbfs/src/app/download/gbfs_v2_2.rs Adds GBFS 2.2 feed types and retrieval.
rust/bambam-gbfs/src/app/download/gbfs_record.rs Unifies versioned feeds for import.
rust/bambam-gbfs/src/app/download/entry_point.rs Defines manifest and GBFS entry points.
rust/bambam-gbfs/src/app/download/download_metadata.rs Detects feed versions before dispatch.
rust/bambam-gbfs/Cargo.toml Adds GBFS implementation dependencies.
Suppressed comments (3)

rust/bambam-gbfs/src/model/gbfs/lookup.rs:99

  • A zone with only one temporal bound is treated as always active. For example, a future start with no end currently matches before it starts, and an expired end with no start continues matching forever. Apply each bound independently.
    rust/bambam-gbfs/src/app/download/run.rs:202
  • Unlike gbfs_download_import, this batch command never creates its advertised output directory. A new/nonexistent --output-directory makes every write fail after all downloads have completed. Create the directory before writing results.
    for result in results.into_iter() {

rust/bambam-gbfs/src/app/download/run.rs:206

  • system_id is feed-controlled data and is joined directly onto the output directory. Values such as ../target or absolute paths can escape out_dir and overwrite arbitrary files. Validate that the ID is exactly one normal path component, or encode it into a safe filename, before joining it.
            let filename = result.system_id();
            let filepath = out_dir.join(&filename);

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread rust/bambam-gbfs/src/model/gbfs/lookup.rs
Comment thread rust/bambam-gbfs/src/model/constraint/gbfs_constraint/engine.rs Outdated
Comment thread rust/bambam-gbfs/src/model/traversal/gbfs_traversal/engine.rs Outdated
Comment thread rust/bambam-gbfs/src/model/traversal/gbfs_traversal/engine.rs Outdated
Comment thread rust/bambam-gbfs/src/app/download/gbfs_v2_2.rs
Comment thread rust/bambam-gbfs/src/app/download/run.rs
Comment thread rust/bambam-gbfs/src/app/download/gbfs_v2_3.rs Outdated
Rob Fitzgerald and others added 14 commits August 13, 2026 12:51
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@robfitzgerald
robfitzgerald merged commit abbd4c3 into main Aug 27, 2026
1 check passed
@robfitzgerald
robfitzgerald deleted the rjf/gbfs branch August 27, 2026 22:18
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.

2 participants