Skip to content

Export a single file for each disruption - #1419

Open
zyxw59 wants to merge 25 commits into
masterfrom
emily-disruption-export
Open

Export a single file for each disruption#1419
zyxw59 wants to merge 25 commits into
masterfrom
emily-disruption-export

Conversation

@zyxw59

@zyxw59 zyxw59 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary of changes

Asana Ticket: 🏹Arrow produces single file describing a disruption

Adds a new API endpoint, /api/disruption/:id, which returns a JSON object containing all the data needed by GTFS creator related to that disruption.

Reviewer Checklist

  • Meets ticket's acceptance criteria
  • Any new or changed functions have typespecs
  • Tests were added for any new functionality (don't just rely on Codecov)
  • This branch was deployed to the staging environment and is currently running with no unexpected increase in warnings, and no errors or crashes.

@zyxw59

zyxw59 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author
Example JSON from this API

{
  "data": {
    "attributes": {
      "description": "GL closed west of North Station, except Babcock-BC and Kenmore-Riverside. B and C shuttles to Copley and Back Bay. \n\nExtra OL service. Mon-Th and Friday services activated here.",
      "hastus_exports": [
        "https://s3.amazonaws.com/mbta-arrow/dev/local/ecfleischman/hastus-export-uploads/1785784414_1785266462_2026-summer-gl-aug8-16_disruption_82_disruption_1.zip?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAWKDUC67O3JECNUFK%2F20260804%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260804T180533Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=1230f6ce4b1301b8e88c8cac9fca53aaee8a866d3147df139e9165ff57311b94"
      ],
      "mode": "subway",
      "status": "pending",
      "title": "Central Subway surge, 8/8 - 8/16/26",
      "trainsformer_exports": []
    },
    "id": "1",
    "relationships": {
      "limits": {
        "data": []
      },
      "replacement_services": {
        "data": [
          {
            "id": "1",
            "type": "replacement_service"
          }
        ]
      },
      "shuttles": {
        "data": [
          {
            "id": "1",
            "type": "shuttle"
          }
        ]
      }
    },
    "type": "disruption_v2"
  },
  "included": [
    {
      "attributes": {
        "destination": "Babcock St",
        "direction_desc": "Outbound",
        "direction_id": "0",
        "shape_id": "BackBayToBabcock-S",
        "waypoint": "Copley"
      },
      "id": "1",
      "relationships": {
        "route_stops": {
          "data": [
            {
              "id": "1",
              "type": "shuttle_route_stop"
            },
            {
              "id": "2",
              "type": "shuttle_route_stop"
            },
            {
              "id": "3",
              "type": "shuttle_route_stop"
            },
            {
              "id": "4",
              "type": "shuttle_route_stop"
            },
            {
              "id": "5",
              "type": "shuttle_route_stop"
            },
            {
              "id": "6",
              "type": "shuttle_route_stop"
            },
            {
              "id": "7",
              "type": "shuttle_route_stop"
            },
            {
              "id": "8",
              "type": "shuttle_route_stop"
            }
          ]
        }
      },
      "type": "shuttle_route"
    },
    {
      "attributes": {
        "direction_id": "1",
        "display_stop_id": null,
        "stop_sequence": 1,
        "time_to_next_stop": "142"
      },
      "id": "9",
      "relationships": {
        "gtfs_stop": {
          "data": {
            "id": "934",
            "type": "gtfs_stop"
          }
        },
        "stop": {
          "data": null
        }
      },
      "type": "shuttle_route_stop"
    },
    {
      "attributes": {
        "lat": 42.350162,
        "lon": -71.10663,
        "name": "Commonwealth Ave @ St Mary's St"
      },
      "id": "953",
      "type": "gtfs_stop"
    },
    {
      "attributes": {
        "direction_id": "1",
        "display_stop_id": null,
        "stop_sequence": 6,
        "time_to_next_stop": "256"
      },
      "id": "14",
      "relationships": {
        "gtfs_stop": {
          "data": null
        },
        "stop": {
          "data": {
            "id": "215",
            "type": "stops"
          }
        }
      },
      "type": "shuttle_route_stop"
    },
    {
      "attributes": {
        "lat": 42.349788,
        "lon": -71.106391,
        "name": "Commonwealth Ave @ St Mary's St"
      },
      "id": "938",
      "type": "gtfs_stop"
    },
    {
      "attributes": {
        "direction_id": "0",
        "display_stop_id": null,
        "stop_sequence": 5,
        "time_to_next_stop": "30"
      },
      "id": "5",
      "relationships": {
        "gtfs_stop": {
          "data": {
            "id": "952",
            "type": "gtfs_stop"
          }
        },
        "stop": {
          "data": null
        }
      },
      "type": "shuttle_route_stop"
    },
    {
      "attributes": {
        "lat": 42.34897,
        "lon": -71.099643,
        "name": "Commonwealth Ave @ Blandford St"
      },
      "id": "941",
      "type": "gtfs_stop"
    },
    {
      "attributes": {
        "lat": 42.349397,
        "lon": -71.103055,
        "name": "Commonwealth Ave @ Hinsdale St"
      },
      "id": "939",
      "type": "gtfs_stop"
    },
    {
      "attributes": {
        "direction_id": "0",
        "display_stop_id": null,
        "stop_sequence": 3,
        "time_to_next_stop": "71"
      },
      "id": "3",
      "relationships": {
        "gtfs_stop": {
          "data": null
        },
        "stop": {
          "data": {
            "id": "214",
            "type": "stops"
          }
        }
      },
      "type": "shuttle_route_stop"
    },
    {
      "attributes": {
        "lat": 42.348245,
        "lon": -71.076218,
        "name": "Stuart St @ Dartmouth St"
      },
      "id": "71855",
      "type": "gtfs_stop"
    },
    {
      "attributes": {
        "lat": 42.349458,
        "lon": -71.10074,
        "name": "Commonwealth Ave @ Silber Way"
      },
      "id": "951",
      "type": "gtfs_stop"
    },
    {
      "attributes": {
        "end_date": "2026-08-16",
        "reason": null,
        "start_date": "2026-08-08",
        "timetable": null
      },
      "id": "1",
      "relationships": {
        "disruption": {
          "data": {
            "id": "1",
            "type": "disruption_v2"
          }
        },
        "shuttle": {
          "data": {
            "id": "1",
            "type": "shuttle"
          }
        }
      },
      "type": "replacement_service"
    },
    {
      "attributes": {
        "lat": 42.35131,
        "lon": -71.115933,
        "name": "Commonwealth Ave @ Buick St"
      },
      "id": "956",
      "type": "gtfs_stop"
    },
    {
      "attributes": {
        "at_street": "Kenmore Street",
        "inserted_at": "2026-08-03T18:57:47Z",
        "municipality": "Boston",
        "on_street": "Commonwealth Avenue",
        "platform_name": "Westbound Shuttle",
        "stop_desc": "Kenmore - Green Line Westbound Shuttle - Commonwealth Ave @ Kenmore St",
        "stop_id": "9170151",
        "stop_lat": 42.34916,
        "stop_lon": -71.0949,
        "stop_name": "Kenmore - Commonwealth Ave @ Kenmore St",
        "updated_at": "2026-08-03T18:57:47Z"
      },
      "id": "214",
      "type": "stops"
    },
    {
      "attributes": {
        "at_street": "Massachusetts Avenue",
        "inserted_at": "2026-08-03T18:57:47Z",
        "municipality": "Boston",
        "on_street": "Commonwealth Avenue",
        "platform_name": "Westbound Shuttle",
        "stop_desc": "Hynes - Green Line Westbound Shuttle - Commonwealth Ave @ Massachusetts Ave",
        "stop_id": "9170153",
        "stop_lat": 42.34937,
        "stop_lon": -71.088504,
        "stop_name": "Hynes - Commonwealth Ave @ Massachusetts Ave",
        "updated_at": "2026-08-03T18:57:47Z"
      },
      "id": "216",
      "type": "stops"
    },
    {
      "attributes": {
        "at_street": "Massachusetts Avenue",
        "inserted_at": "2026-08-03T18:57:47Z",
        "municipality": "Boston",
        "on_street": "Commonwealth Avenue",
        "platform_name": "Park Street & North Shuttle",
        "stop_desc": "Hynes - Green Line Park Street & North Shuttle - Commonwealth Ave @ Massachusetts Ave",
        "stop_id": "9170152",
        "stop_lat": 42.34889,
        "stop_lon": -71.08835,
        "stop_name": "Hynes - Commonwealth Ave @ Massachusetts Ave",
        "updated_at": "2026-08-03T18:57:47Z"
      },
      "id": "215",
      "type": "stops"
    },
    {
      "attributes": {
        "direction_id": "0",
        "display_stop_id": null,
        "stop_sequence": 4,
        "time_to_next_stop": "31"
      },
      "id": "4",
      "relationships": {
        "gtfs_stop": {
          "data": {
            "id": "951",
            "type": "gtfs_stop"
          }
        },
        "stop": {
          "data": null
        }
      },
      "type": "shuttle_route_stop"
    },
    {
      "attributes": {
        "direction_id": "0",
        "display_stop_id": null,
        "stop_sequence": 8,
        "time_to_next_stop": null
      },
      "id": "8",
      "relationships": {
        "gtfs_stop": {
          "data": {
            "id": "933",
            "type": "gtfs_stop"
          }
        },
        "stop": {
          "data": null
        }
      },
      "type": "shuttle_route_stop"
    },
    {
      "attributes": {
        "lat": 42.349831,
        "lon": -71.103801,
        "name": "Commonwealth Ave @ Granby St"
      },
      "id": "952",
      "type": "gtfs_stop"
    },
    {
      "attributes": {
        "direction_id": "1",
        "display_stop_id": null,
        "stop_sequence": 3,
        "time_to_next_stop": "36"
      },
      "id": "11",
      "relationships": {
        "gtfs_stop": {
          "data": {
            "id": "939",
            "type": "gtfs_stop"
          }
        },
        "stop": {
          "data": null
        }
      },
      "type": "shuttle_route_stop"
    },
    {
      "attributes": {
        "lat": 42.35123,
        "lon": -71.118201,
        "name": "Commonwealth Ave @ Pleasant St"
      },
      "id": "934",
      "type": "gtfs_stop"
    },
    {
      "attributes": {
        "disrupted_route_id": "Green-B",
        "shuttle_name": "BabcockStToBackBayviaCopley-S",
        "status": "active",
        "suffix": null
      },
      "id": "1",
      "relationships": {
        "routes": {
          "data": [
            {
              "id": "1",
              "type": "shuttle_route"
            },
            {
              "id": "2",
              "type": "shuttle_route"
            }
          ]
        }
      },
      "type": "shuttle"
    },
    {
      "attributes": {
        "direction_id": "0",
        "display_stop_id": null,
        "stop_sequence": 1,
        "time_to_next_stop": "196"
      },
      "id": "1",
      "relationships": {
        "gtfs_stop": {
          "data": {
            "id": "71855",
            "type": "gtfs_stop"
          }
        },
        "stop": {
          "data": null
        }
      },
      "type": "shuttle_route_stop"
    },
    {
      "attributes": {
        "direction_id": "1",
        "display_stop_id": null,
        "stop_sequence": 7,
        "time_to_next_stop": null
      },
      "id": "15",
      "relationships": {
        "gtfs_stop": {
          "data": {
            "id": "71855",
            "type": "gtfs_stop"
          }
        },
        "stop": {
          "data": null
        }
      },
      "type": "shuttle_route_stop"
    },
    {
      "attributes": {
        "direction_id": "0",
        "display_stop_id": null,
        "stop_sequence": 2,
        "time_to_next_stop": "109"
      },
      "id": "2",
      "relationships": {
        "gtfs_stop": {
          "data": null
        },
        "stop": {
          "data": {
            "id": "216",
            "type": "stops"
          }
        }
      },
      "type": "shuttle_route_stop"
    },
    {
      "attributes": {
        "destination": "Back Bay",
        "direction_desc": "Inbound",
        "direction_id": "1",
        "shape_id": "BabcockToBackBay-S",
        "waypoint": "Copley"
      },
      "id": "2",
      "relationships": {
        "route_stops": {
          "data": [
            {
              "id": "9",
              "type": "shuttle_route_stop"
            },
            {
              "id": "10",
              "type": "shuttle_route_stop"
            },
            {
              "id": "11",
              "type": "shuttle_route_stop"
            },
            {
              "id": "12",
              "type": "shuttle_route_stop"
            },
            {
              "id": "13",
              "type": "shuttle_route_stop"
            },
            {
              "id": "14",
              "type": "shuttle_route_stop"
            },
            {
              "id": "15",
              "type": "shuttle_route_stop"
            }
          ]
        }
      },
      "type": "shuttle_route"
    },
    {
      "attributes": {
        "direction_id": "1",
        "display_stop_id": null,
        "stop_sequence": 4,
        "time_to_next_stop": "59"
      },
      "id": "12",
      "relationships": {
        "gtfs_stop": {
          "data": {
            "id": "941",
            "type": "gtfs_stop"
          }
        },
        "stop": {
          "data": null
        }
      },
      "type": "shuttle_route_stop"
    },
    {
      "attributes": {
        "direction_id": "1",
        "display_stop_id": null,
        "stop_sequence": 5,
        "time_to_next_stop": "90"
      },
      "id": "13",
      "relationships": {
        "gtfs_stop": {
          "data": null
        },
        "stop": {
          "data": {
            "id": "110",
            "type": "stops"
          }
        }
      },
      "type": "shuttle_route_stop"
    },
    {
      "attributes": {
        "at_street": "Kenmore Street",
        "inserted_at": "2026-08-03T18:57:47Z",
        "municipality": "Boston",
        "on_street": "Commonwealth Avenue",
        "platform_name": "Green Line Shuttle",
        "stop_desc": "Kenmore - Green Line Shuttle - 512 Commonwealth Ave",
        "stop_id": "9070150",
        "stop_lat": 42.348712,
        "stop_lon": -71.095526,
        "stop_name": "Kenmore - 512 Commonwealth Ave",
        "updated_at": "2026-08-03T18:57:47Z"
      },
      "id": "110",
      "type": "stops"
    },
    {
      "attributes": {
        "lat": 42.351568,
        "lon": -71.121168,
        "name": "Commonwealth Ave @ Babcock St"
      },
      "id": "933",
      "type": "gtfs_stop"
    },
    {
      "attributes": {
        "direction_id": "0",
        "display_stop_id": null,
        "stop_sequence": 7,
        "time_to_next_stop": "59"
      },
      "id": "7",
      "relationships": {
        "gtfs_stop": {
          "data": {
            "id": "956",
            "type": "gtfs_stop"
          }
        },
        "stop": {
          "data": null
        }
      },
      "type": "shuttle_route_stop"
    },
    {
      "attributes": {
        "direction_id": "0",
        "display_stop_id": null,
        "stop_sequence": 6,
        "time_to_next_stop": "107"
      },
      "id": "6",
      "relationships": {
        "gtfs_stop": {
          "data": {
            "id": "953",
            "type": "gtfs_stop"
          }
        },
        "stop": {
          "data": null
        }
      },
      "type": "shuttle_route_stop"
    },
    {
      "attributes": {
        "direction_id": "1",
        "display_stop_id": null,
        "stop_sequence": 2,
        "time_to_next_stop": "33"
      },
      "id": "10",
      "relationships": {
        "gtfs_stop": {
          "data": {
            "id": "938",
            "type": "gtfs_stop"
          }
        },
        "stop": {
          "data": null
        }
      },
      "type": "shuttle_route_stop"
    }
  ],
  "jsonapi": {
    "version": "1.0"
  }
}

@zyxw59
zyxw59 marked this pull request as ready for review August 4, 2026 18:41
@zyxw59
zyxw59 requested a review from a team as a code owner August 4, 2026 18:41
@zyxw59
zyxw59 requested review from khansen-mbta and removed request for a team August 4, 2026 18:41
@zyxw59

zyxw59 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Oops, I just realized I forgot the UI component of this ticket

@zyxw59
zyxw59 requested review from a team and rudiejd and removed request for a team August 5, 2026 21:12
@zyxw59

zyxw59 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

I am no frontend dev, so I'd appreciate any feedback on better UX/design for the download button.

@rudiejd

rudiejd commented Aug 6, 2026

Copy link
Copy Markdown
Member

I can't deploy your change to a lower environment:
image

Maybe you need to rebase off of master to get @lemald 's changes to the deploy process?

@zyxw59

zyxw59 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Actually, hold on a bit before testing, I'm realizing I have some issues in the query so it's not returning all the necessary data.

Comment thread lib/arrow_web/controllers/api/disruption_v2_controller.ex
Comment thread lib/arrow_web/controllers/api_json/disruptionv2_view.ex Outdated
alias Plug.Conn

@spec index(Conn.t(), map()) :: Conn.t()
def index(conn, %{"id" => id}) do

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.

issue: running locally, I noticed this endpoint crashes if the disruption does not exist. it should return a 404 instead of crashing.

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.

I think that is expected behavior when running locally — if you set debug_errors: false in config/dev.exs, it will return a 404. You can also see this behavior with the frontend /disruption/:id endpoint, where it shows a stack trace when running locally but a 404 in deployed environments.

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.

image The new endpoint does give a 400 now when I supply a nonexistent ID... this is better than crashing, but I would still prefer the more descriptive 404

@zyxw59

zyxw59 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

also, question: will the presigned s3 link be re-generated on every query? If so, we might need to consider using the S3 URI instead of a presigned link, so that gtfs_creator can better cache stuff

This is only a problem if we need to make changes to a disruption that we've already included in gtfs inputs, right?

Anyway, this is the same logic as the existing /api/service-schedules and /api/trainsformer-service-schedules endpoints, but I guess it's not a problem now since we aren't doing any caching in gtfs creator yet.

I think changing it to return an S3 URI is fine, but it will require changes in the corresponding parts of gtfs creator (hastus/update.py and trainsformer/update.py), and doing so in a way that's still compatible with the presigned links from the old APIs

zyxw59 added 3 commits August 6, 2026 14:57
I think the joins were just making things more difficult to read, and I
don't think there's a benefit to doing them in a single query rather
than in separate queries in the preload.
@rudiejd

rudiejd commented Aug 11, 2026

Copy link
Copy Markdown
Member

issue: endpoint should include S3 URI for the shape instead of the shape ID. gtfs_inputs needs to track the S3 URI for versioning shapes, because the S3 URI must change every time a shape is changed whereas the arrow shape_id need not change

@zyxw59

zyxw59 commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

I just realized that I missed a usage of the arrow API, in gtfs_creator2/disruptions/disruptions.py, the arrow_replacement_services and arrow_trainsformer_replacement_services functions. I had mistakenly thought that the service_schedules.json and trainsformer_service_schedules.json files that GTFS creator downloads from Arrow were only used for getting the HASTUS and Trainsformer export URIs, so I didn't include the other fields. I'll need to update this to re-add those fields.

Or alternatively, the service_schedules.json and trainsformer_service_schedules.json outputs already exist, and while they don't correspond to an individual disruption, they are approximately static exports of parts of Arrow's state.

@rudiejd

rudiejd commented Aug 11, 2026

Copy link
Copy Markdown
Member

@zyxw59 I think we would want to include the other information from the service schedule APIs in addition to the S3 URI - this information tells gtfs_creator which days the replacement services should be running. This information is not static, since a user can go in and change the days on which a service should be running. you will also want to include all of the information for a replacement_service (times when a shuttle is running, which are defined in arrow)

@zyxw59

zyxw59 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

Augh, after drilling down into all the things we need this API to produce, I think I'm appreciating your distaste for JSON API 🙃

@zyxw59

zyxw59 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

I think I'm going to majorly refactor this away from JSON API

@zyxw59

zyxw59 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

Hmm, I keep discovering more places in GTFS Creator that are calling the Arrow API. Specifically archived_shuttle_routes, which creates canonical service for the shuttle routes that are present in Arrow but not in the GTFS feed. @rudiejd do you have any ideas on how we want to handle that, since those shuttles won't be associated with any active disruptions?

@rudiejd

rudiejd commented Aug 12, 2026

Copy link
Copy Markdown
Member

no worries! I think that's totally acceptable, and I had a similar realization on a previous arrow PR I did

@zyxw59

zyxw59 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

And one more usage that isn't directly tied to specific disruptions: The /api/shuttle-stops endpoint, which is called directly from the makefile, and used by gtfs_creator2/merge/replacement_bus_stops.py

@zyxw59

zyxw59 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

@rudiejd how do you think we should handle those uses that aren't tied to a specific disruption (archived shuttle routes and merge replacement bus stops)?

@zyxw59

zyxw59 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Actually, as I think about this a bit more, an Arrow shuttle isn't really tied to a single disruption– the same shuttle could be included in multiple disruptions, so maybe it makes sense to leave the shuttles out of this endpoint.

In particular, I'm imagining a scenario where there are two disruptions that use the same shuttle, and then there is a change to the shuttle but only one of the disruption exports is updated, so now there are two shuttles with the same IDs but different definitions.

@rudiejd

rudiejd commented Aug 13, 2026

Copy link
Copy Markdown
Member

Yeah, I probably hadn't thought through this completely... only the activation of the shuttle is really tied to the disruption. I think one approach could be to handle the shapes, archived shuttles, and all of the shuttle data separately. what would you think about storing the shuttle as a separate entity in S3, and then having the disruption API reference the S3 URI of that entity?

@rudiejd

rudiejd commented Aug 13, 2026

Copy link
Copy Markdown
Member

The alternative (and maybe a simpler approach) to that would be that we consider each disruption to include its own snapshot of the shuttles, so we just include all of the shuttle information on this endpoint regardless of whether it might be different in a different disruption. This is more along the lines of what I was thinking

@zyxw59

zyxw59 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

The alternative (and maybe a simpler approach) to that would be that we consider each disruption to include its own snapshot of the shuttles, so we just include all of the shuttle information on this endpoint regardless of whether it might be different in a different disruption. This is more along the lines of what I was thinking

I think the issue there is that if two disruptions have a different snapshot of the same shuttle, then GTFS creator will try to create two routes with the same ID but different definitions.

@zyxw59

zyxw59 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Yeah, I probably hadn't thought through this completely... only the activation of the shuttle is really tied to the disruption. I think one approach could be to handle the shapes, archived shuttles, and all of the shuttle data separately. what would you think about storing the shuttle as a separate entity in S3, and then having the disruption API reference the S3 URI of that entity?

I don't think we need/want to store the shuttles in S3. I think the shuttle definitions could just be JSON files downloaded from Arrow and stored in the GTFS inputs repo.

@rudiejd

rudiejd commented Aug 13, 2026

Copy link
Copy Markdown
Member

I think the issue there is that if two disruptions have a different snapshot of the same shuttle, then GTFS creator will try to create two routes with the same ID but different definitions.

ahhhhhh yeah. we could have some logic to avoid a collision in gtfs_creator in this case? though maybe that's just working around something that shouldn't be possible

@rudiejd

rudiejd commented Aug 13, 2026

Copy link
Copy Markdown
Member

I don't think we need/want to store the shuttles in S3. I think the shuttle definitions could just be JSON files downloaded from Arrow and stored in the GTFS inputs repo.

yeah that makes more sense. Ignore the S3 part, I think I might have been too focused on what we're doing in this PR. But same idea. In this case, you could just reference the shuttle by name in the disruption API. Or we could use Arrow's auto-increment ID as a unique identifier for the shuttles if you think that's better.

],
limits: [:limit_day_of_weeks],
replacement_services: [
shuttle: [routes: [:shape, route_stops: [:stop]]]

@rudiejd rudiejd Aug 13, 2026

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.

if we're not using this preload, could you remove it? namely, I think only the shuttle name should matter

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.

No, it's needed for getting the timetables for the replacement service.

Though we can get rid of shape.

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.

But maybe we don't want to be including the timetables in this export? They are quite large (for the Green Line disruption I'm using for testing, ~378 kB, vs >2 kB for all the rest of the export data).

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.

Maybe we could upload the timetables to S3 as well?

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.

hmm, I think we should be fine since this is probably one of the bigger disruptions and it's still well under the github file limit. This is about the size of the Southside base schedules, which we already store multiple copies of in this repo with no noticable problems in clone / commit speed
image

@rudiejd rudiejd Aug 13, 2026

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 think it's really only when we get files on the order of 10MB+ that I start to notice a problem

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.

Lol fair enough

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.

I guess there is also the question of whether GitHub will show diffs for files that big, but we might just not care that much about that (ideally disruption exports are not frequently modified once they've been created)

@rudiejd
rudiejd deployed to dev-green August 14, 2026 14:30 — with GitHub Actions Active
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