From d37a2d9e5691ce58c2e53b6b882a53cd58ede92b Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 13 Feb 2026 10:32:27 -0500 Subject: [PATCH 01/13] fix: add missing docs for last_trip attr in /predictions (#965) --- .../lib/api_web/controllers/prediction_controller.ex | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/api_web/lib/api_web/controllers/prediction_controller.ex b/apps/api_web/lib/api_web/controllers/prediction_controller.ex index d9397820..4c1e7391 100644 --- a/apps/api_web/lib/api_web/controllers/prediction_controller.ex +++ b/apps/api_web/lib/api_web/controllers/prediction_controller.ex @@ -330,6 +330,12 @@ defmodule ApiWeb.PredictionController do example: 60 ) + last_trip( + :boolean, + "Indicates whether this is a prediction for the last trip before the end of service.", + example: true + ) + schedule_relationship( :string, """ From b4a60340371bd0e070aa4d3ef0b5e2a92e7cc7fa Mon Sep 17 00:00:00 2001 From: Eddie Maldonado Date: Thu, 12 Feb 2026 10:52:40 -0500 Subject: [PATCH 02/13] fix: exclude stops from NS <-> Swampscott local shuttle --- apps/state/config/config.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/state/config/config.exs b/apps/state/config/config.exs index 1f4649a0..3181fd62 100644 --- a/apps/state/config/config.exs +++ b/apps/state/config/config.exs @@ -199,7 +199,7 @@ config :state, :stops_on_route, "Shuttle-LynnSwampscott-0-" => true, "Shuttle-NorthStationSwampscott-0-" => true, "Shuttle-NorthStationSwampscottLimited-0-" => true, - "Shuttle-NorthStationSwampscottLocal-0-" => true, + "Shuttle-NorthStationSwampscottLocal-0-" => false, "Shuttle-NorthStationSwampscottExpress-0-" => true, "CR-Newburyport-adde8a7c-" => true, "CR-Newburyport-76fa2c91-" => true, From 135212761efc3ae7f58b5c03ee40ad073c984049 Mon Sep 17 00:00:00 2001 From: Eddie Maldonado Date: Thu, 12 Feb 2026 11:04:31 -0500 Subject: [PATCH 03/13] fix: Foxboro goes between Windsor Gardens and Walpole --- apps/state/config/config.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/state/config/config.exs b/apps/state/config/config.exs index 3181fd62..62114ef1 100644 --- a/apps/state/config/config.exs +++ b/apps/state/config/config.exs @@ -283,10 +283,10 @@ config :state, :stops_on_route, "place-FB-0109" ], ["place-FB-0148", "place-FB-0166", "place-FB-0177", "place-FB-0191"], - ["place-FB-0191", "place-FS-0049", "place-FB-0230"] + ["place-FB-0166", "place-FS-0049", "place-FB-0191"] ], {"CR-Franklin", 1} => [ - ["place-FB-0230", "place-FS-0049", "place-FB-0191"], + ["place-FB-0191", "place-FS-0049", "place-FB-0166"], [ "place-FB-0109", "place-DB-0095", From 9dc47c61cbb6e1fa19428efd951744a5049bd35d Mon Sep 17 00:00:00 2001 From: Eddie Maldonado Date: Thu, 12 Feb 2026 11:11:15 -0500 Subject: [PATCH 04/13] fix: include Fairmount stops on Franklin Line --- apps/state/config/config.exs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/state/config/config.exs b/apps/state/config/config.exs index 62114ef1..cb5e37ed 100644 --- a/apps/state/config/config.exs +++ b/apps/state/config/config.exs @@ -258,6 +258,9 @@ config :state, :stops_on_route, "Shuttle-ForgeParkWalpole-0-" => true, "CR-Franklin-3badde55-" => true, "CR-Franklin-02118599-" => true, + # Franklin line via Fairmount + "CR-Franklin-807421e2-" => true, + "CR-Franklin-901f1692-" => true, # Worcester Line shuttles "Shuttle-AshlandFramingham-0-" => true, "Shuttle-FraminghamSouthStationExpress-0-" => true, From 9a2625eccc6339c24024f28c1fd89d2a75a1601c Mon Sep 17 00:00:00 2001 From: Eddie Maldonado Date: Thu, 12 Feb 2026 12:11:50 -0500 Subject: [PATCH 05/13] fix: don't consider Dedham Corp Center to be on Fairmount --- apps/state/config/config.exs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/state/config/config.exs b/apps/state/config/config.exs index cb5e37ed..254ee127 100644 --- a/apps/state/config/config.exs +++ b/apps/state/config/config.exs @@ -534,7 +534,8 @@ config :state, :stops_on_route, "place-FB-0303", "place-FB-0275", "place-FB-0230", - "place-FB-0191" + "place-FB-0191", + "place-FB-0118" ], {"CR-Fairmount", 1} => [ "place-FB-0166", @@ -545,7 +546,8 @@ config :state, :stops_on_route, "place-FB-0303", "place-FB-0275", "place-FB-0230", - "place-FB-0191" + "place-FB-0191", + "place-FB-0118" ], {"CR-Lowell", 0} => [ "place-WR-0205", From 1084fe99c202f7907f3f39e8a32bffdd0fa7f998 Mon Sep 17 00:00:00 2001 From: Eddie Maldonado Date: Thu, 12 Feb 2026 13:40:43 -0500 Subject: [PATCH 06/13] fix: fix test --- apps/state/test/state/stops_on_route_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/state/test/state/stops_on_route_test.exs b/apps/state/test/state/stops_on_route_test.exs index 8947da46..5416f284 100644 --- a/apps/state/test/state/stops_on_route_test.exs +++ b/apps/state/test/state/stops_on_route_test.exs @@ -345,7 +345,7 @@ defmodule State.StopsOnRouteTest do test "can drop stops from a route" do trip_id = "fairmont-trip" - stop_ids = ["place-sstat", "place-FB-0109", "place-FB-0118"] + stop_ids = ["place-sstat", "place-DB-2205", "place-FB-0109"] State.Stop.new_state(for stop_id <- stop_ids, do: %Model.Stop{id: stop_id}) State.Route.new_state([%Model.Route{id: "CR-Fairmount"}]) @@ -360,7 +360,7 @@ defmodule State.StopsOnRouteTest do stop_ids = by_route_id("CR-Fairmount") - assert stop_ids == ["place-sstat", "place-FB-0118"] + assert stop_ids == ["place-sstat", "place-DB-2205"] end end From 37867d2a7f430fb00536db9553fff5e35fbfe652 Mon Sep 17 00:00:00 2001 From: Eddie Maldonado Date: Tue, 17 Feb 2026 11:29:51 -0500 Subject: [PATCH 07/13] fix: try removing unnecessary `place-sstat` --- apps/state/config/config.exs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/state/config/config.exs b/apps/state/config/config.exs index 254ee127..25f2d613 100644 --- a/apps/state/config/config.exs +++ b/apps/state/config/config.exs @@ -300,8 +300,7 @@ config :state, :stops_on_route, "place-DB-2249", "place-DB-2258", "place-DB-2265", - "place-NEC-2203", - "place-sstat" + "place-NEC-2203" ] ], {"CR-Fairmount", 0} => [ From e8e513b9c27dd53fadd4aab372238f9e14f123a7 Mon Sep 17 00:00:00 2001 From: Eddie Maldonado Date: Tue, 17 Feb 2026 15:47:58 -0500 Subject: [PATCH 08/13] fix: just specify all stop ordering in direction 1 --- apps/state/config/config.exs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/state/config/config.exs b/apps/state/config/config.exs index 25f2d613..0706ba7f 100644 --- a/apps/state/config/config.exs +++ b/apps/state/config/config.exs @@ -289,8 +289,17 @@ config :state, :stops_on_route, ["place-FB-0166", "place-FS-0049", "place-FB-0191"] ], {"CR-Franklin", 1} => [ - ["place-FB-0191", "place-FS-0049", "place-FB-0166"], [ + "place-FB-0303", + "place-FB-0275", + "place-FB-0230", + "place-FB-0191", + "place-FS-0049", + "place-FB-0166", + "place-FB-0148", + "place-FB-0143", + "place-FB-0125", + "place-FB-0118", "place-FB-0109", "place-DB-0095", "place-DB-2205", @@ -300,7 +309,11 @@ config :state, :stops_on_route, "place-DB-2249", "place-DB-2258", "place-DB-2265", - "place-NEC-2203" + "place-NEC-2203", + "place-forhl", + "place-rugg", + "place-bbsta", + "place-sstat" ] ], {"CR-Fairmount", 0} => [ From b3bf2fcffc72df1ad7170c48adf2fadc42248b71 Mon Sep 17 00:00:00 2001 From: Eddie Maldonado Date: Wed, 18 Feb 2026 15:36:17 -0500 Subject: [PATCH 09/13] fix: more explicit override to prevent Hyde Park from sorting to end --- apps/state/lib/state/stops_on_route.ex | 70 +++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 8 deletions(-) diff --git a/apps/state/lib/state/stops_on_route.ex b/apps/state/lib/state/stops_on_route.ex index c77a8a91..ef67fa9e 100644 --- a/apps/state/lib/state/stops_on_route.ex +++ b/apps/state/lib/state/stops_on_route.ex @@ -448,14 +448,68 @@ defmodule State.StopsOnRoute do end def merge_ids(lists_of_ids, override_lists) do - sorted_lists = Enum.sort_by(lists_of_ids, &list_merge_key/1, &>=/2) - # overrides should be short or empty, so putting that first with ++ is - # fine. - lists_with_overrides = override_lists ++ sorted_lists - - lists_with_overrides - |> Enum.reduce(&merge_two_lists/2) - |> Enum.uniq() + if [ + "place-sstat", + "place-bbsta", + "place-rugg", + "place-forhl", + "place-NEC-2203", + "place-DB-2265", + "place-DB-2258", + "place-DB-2249", + "place-DB-2240", + "place-DB-2230", + "place-DB-2222", + "place-DB-2205", + "place-DB-0095", + "place-FB-0109", + "place-FB-0118", + "place-FB-0125", + "place-FB-0143", + "place-FB-0148", + "place-FB-0166", + "place-FS-0049", + "place-FB-0191", + "place-FB-0230", + "place-FB-0275", + "place-FB-0303" + ] in lists_of_ids do + [ + "place-FB-0303", + "place-FB-0275", + "place-FB-0230", + "place-FB-0191", + "place-FS-0049", + "place-FB-0166", + "place-FB-0148", + "place-FB-0143", + "place-FB-0125", + "place-FB-0118", + "place-FB-0109", + "place-DB-0095", + "place-DB-2205", + "place-DB-2222", + "place-DB-2230", + "place-DB-2240", + "place-DB-2249", + "place-DB-2258", + "place-DB-2265", + "place-NEC-2203", + "place-forhl", + "place-rugg", + "place-bbsta", + "place-sstat" + ] + else + sorted_lists = Enum.sort_by(lists_of_ids, &list_merge_key/1, &>=/2) + # overrides should be short or empty, so putting that first with ++ is + # fine. + lists_with_overrides = override_lists ++ sorted_lists + + lists_with_overrides + |> Enum.reduce(&merge_two_lists/2) + |> Enum.uniq() + end end @spec list_merge_key(stop_id_list) :: From 2f150ce6ccf610c82e2a2fb29b090729339c1c8a Mon Sep 17 00:00:00 2001 From: Eddie Maldonado Date: Wed, 18 Feb 2026 15:38:29 -0500 Subject: [PATCH 10/13] chore: also specify all stop ordering in direction 0 --- apps/state/config/config.exs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/state/config/config.exs b/apps/state/config/config.exs index 0706ba7f..490167ec 100644 --- a/apps/state/config/config.exs +++ b/apps/state/config/config.exs @@ -274,6 +274,10 @@ config :state, :stops_on_route, stop_order_overrides: %{ {"CR-Franklin", 0} => [ [ + "place-sstat", + "place-bbsta", + "place-rugg", + "place-forhl", "place-NEC-2203", "place-DB-2265", "place-DB-2258", @@ -283,10 +287,18 @@ config :state, :stops_on_route, "place-DB-2222", "place-DB-2205", "place-DB-0095", - "place-FB-0109" - ], - ["place-FB-0148", "place-FB-0166", "place-FB-0177", "place-FB-0191"], - ["place-FB-0166", "place-FS-0049", "place-FB-0191"] + "place-FB-0109", + "place-FB-0118", + "place-FB-0125", + "place-FB-0143", + "place-FB-0148", + "place-FB-0166", + "place-FS-0049", + "place-FB-0191", + "place-FB-0230", + "place-FB-0275", + "place-FB-0303" + ] ], {"CR-Franklin", 1} => [ [ From 0a9be3c44c74a2d9e9ea8d602e736172beb6120b Mon Sep 17 00:00:00 2001 From: Eddie Maldonado Date: Wed, 18 Feb 2026 15:44:20 -0500 Subject: [PATCH 11/13] test: drop now-outdated test related to Plimptonville --- apps/state/test/state/stops_on_route_test.exs | 61 ------------------- 1 file changed, 61 deletions(-) diff --git a/apps/state/test/state/stops_on_route_test.exs b/apps/state/test/state/stops_on_route_test.exs index 5416f284..be68fc48 100644 --- a/apps/state/test/state/stops_on_route_test.exs +++ b/apps/state/test/state/stops_on_route_test.exs @@ -282,67 +282,6 @@ defmodule State.StopsOnRouteTest do assert by_route_id(@route.id) == ["other_stop"] end - test "shows Plimptonville after Windsor Gardens even when they don't share a trip" do - State.Stop.new_state([ - %Model.Stop{id: "place-sstat"}, - %Model.Stop{id: "place-FB-0166"}, - %Model.Stop{id: "place-FB-0177"}, - %Model.Stop{id: "place-FB-0191"}, - %Model.Stop{id: "place-FB-0275"} - ]) - - State.Route.new_state([%Model.Route{id: "CR-Franklin"}]) - - State.Trip.new_state([ - %Model.Trip{ - id: "via-plimptonville", - route_id: "CR-Franklin", - direction_id: 0, - service_id: "service" - }, - %Model.Trip{ - id: "via-windsor-gardens", - route_id: "CR-Franklin", - direction_id: 0, - service_id: "service" - } - ]) - - State.Schedule.new_state([ - %Model.Schedule{trip_id: "via-plimptonville", stop_id: "place-sstat", stop_sequence: 1}, - %Model.Schedule{trip_id: "via-plimptonville", stop_id: "place-FB-0177", stop_sequence: 2}, - %Model.Schedule{trip_id: "via-plimptonville", stop_id: "place-FB-0275", stop_sequence: 3}, - # Windsor Gardens trip has more stops because this bug only shows up when the merge - # has windor gardens on the left and plimptonville on the right. - # They're sorted by length before merging, so this forces them to be in the order to make the bug appear. - %Model.Schedule{trip_id: "via-windsor-gardens", stop_id: "place-sstat", stop_sequence: 1}, - %Model.Schedule{ - trip_id: "via-windsor-gardens", - stop_id: "place-FB-0166", - stop_sequence: 2 - }, - %Model.Schedule{ - trip_id: "via-windsor-gardens", - stop_id: "place-FB-0191", - stop_sequence: 3 - }, - %Model.Schedule{ - trip_id: "via-windsor-gardens", - stop_id: "place-FB-0275", - stop_sequence: 4 - } - ]) - - update!() - - stop_ids = by_route_id("CR-Franklin") - - assert Enum.filter(stop_ids, &(&1 in ["place-FB-0166", "place-FB-0177"])) == [ - "place-FB-0166", - "place-FB-0177" - ] - end - test "can drop stops from a route" do trip_id = "fairmont-trip" stop_ids = ["place-sstat", "place-DB-2205", "place-FB-0109"] From a1f60b16cd47296ea16a096b217ca2485726fed9 Mon Sep 17 00:00:00 2001 From: Eddie Maldonado Date: Wed, 18 Feb 2026 15:54:24 -0500 Subject: [PATCH 12/13] fix: reverse order of stops to make integration test happy --- apps/state/lib/state/stops_on_route.ex | 46 +++++++++++++------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/apps/state/lib/state/stops_on_route.ex b/apps/state/lib/state/stops_on_route.ex index ef67fa9e..d0530341 100644 --- a/apps/state/lib/state/stops_on_route.ex +++ b/apps/state/lib/state/stops_on_route.ex @@ -475,30 +475,30 @@ defmodule State.StopsOnRoute do "place-FB-0303" ] in lists_of_ids do [ - "place-FB-0303", - "place-FB-0275", - "place-FB-0230", - "place-FB-0191", - "place-FS-0049", - "place-FB-0166", - "place-FB-0148", - "place-FB-0143", - "place-FB-0125", - "place-FB-0118", - "place-FB-0109", - "place-DB-0095", - "place-DB-2205", - "place-DB-2222", - "place-DB-2230", - "place-DB-2240", - "place-DB-2249", - "place-DB-2258", - "place-DB-2265", - "place-NEC-2203", - "place-forhl", - "place-rugg", + "place-sstat", "place-bbsta", - "place-sstat" + "place-rugg", + "place-forhl", + "place-NEC-2203", + "place-DB-2265", + "place-DB-2258", + "place-DB-2249", + "place-DB-2240", + "place-DB-2230", + "place-DB-2222", + "place-DB-2205", + "place-DB-0095", + "place-FB-0109", + "place-FB-0118", + "place-FB-0125", + "place-FB-0143", + "place-FB-0148", + "place-FB-0166", + "place-FS-0049", + "place-FB-0191", + "place-FB-0230", + "place-FB-0275", + "place-FB-0303" ] else sorted_lists = Enum.sort_by(lists_of_ids, &list_merge_key/1, &>=/2) From a84d56eaae7ec4e7cabf858cec9a13d2c9120aef Mon Sep 17 00:00:00 2001 From: Eddie Maldonado Date: Thu, 19 Feb 2026 08:58:03 -0500 Subject: [PATCH 13/13] fix: empty commit to maybe make GitHub allow me to merge?