Skip to content

fix: preserve stop alerts when location arrivals are empty - #1574

Open
SurajSingh563 wants to merge 2 commits into
OneBusAway:mainfrom
SurajSingh563:fix/1565-location-arrivals-stop-alerts
Open

SurajSingh563 wants to merge 2 commits into
OneBusAway:mainfrom
SurajSingh563:fix/1565-location-arrivals-stop-alerts

Conversation

@SurajSingh563

@SurajSingh563 SurajSingh563 commented Oct 8, 2026 •

Copy link
Copy Markdown

Collect stop alerts on the batched path even when its window contains no
stop times, so quiet location searches keep their situation references.

Fixes #1565

Summary

  • arrivalsForStops returned early when no stop in the area had a stop time in the window, before stop-level alerts were collected. Late-night or no-service queries returned no stop alerts.
  • Stop alerts are now collected on that early-return path too, matching Java, which collects stop alerts for every found stop regardless of arrivals (spec step 7).
  • No difference from the OpenAPI spec or other handlers. This brings arrivals-and-departures-for-location in line with Java.

Changes

  • internal/restapi/arrivals_core.go: extracted the stop-alert loop into addStopAlertsForStops and call it on both the len(allActive) == 0 early return and the normal return. Each path calls it exactly once.
  • internal/restapi/arrivals_and_departures_for_location_handler_test.go: added TestArrivalsAndDeparturesForLocationIncludesStopAlertsWithoutArrivals.

Size: ~56 lines changed (52 additions, 4 deletions)

Understanding

Root cause: The len(allActive) == 0 early return sat above the loop that calls GetAlertsForStop. Alerts were only collected when at least one stop had an arrival, so a quiet area lost its alerts.

Alternatives considered: Moving the loop above the early return would also work. I extracted a helper and called it from both paths so the normal path keeps its existing order (alerts are still collected last) and the early return stays a small change.

Riskiest part of this change: The two call sites in arrivalsForStops. If both ever ran for the same request, alerts would be added twice, but the early return exits before the second call. Look there first if duplicate situations appear.

Testing

  • New test: a stop alert on a stop with a 3 AM query and a 0-minute window. It asserts there are no arrivals, then that the situation ID is in situationIds and resolves in references.situations.
  • Confirmed the test fails before the fix (situation ID and reference both missing) and passes after.
  • go test -tags "sqlite_fts5 sqlite_math_functions" ./internal/restapi -run 'TestArrivalsAndDeparturesForLocation(IncludesStopAlertsWithoutArrivals|EndToEnd|RouteTypeFiltersArrivalsNotStops)$' -count=1
  • arrivalsForStops has a single production caller (the location arrivals handler), so no other call sites are affected.

Response comparison

Region / production server: None. Maglev only; I have no Java OBA server to compare against.
GTFS static feed(s): Maglev test fixture (testdata)
GTFS-RT feed(s): Injected test stop alert on stop 4062
Endpoint(s) exercised: arrivals-and-departures-for-location, quiet window (03:00, minutesBefore=0, minutesAfter=0)

Trimmed to the relevant fields.

Maglev before this PR (main):

Response
{
  "data.entry.arrivalsAndDepartures": [],
  "data.entry.situationIds": [],
  "data.references.situations": []
}

Maglev after this PR:

Response
{
  "data.entry.arrivalsAndDepartures": [],
  "data.entry.situationIds": [
    "25_location-no-arrivals-stop-alert"
  ],
  "data.references.situations": [
    {
      "id": "25_location-no-arrivals-stop-alert",
      "creationTime": 0,
      "activeWindows": [],
      "allAffects": [
        {
          "agencyId": "",
          "applicationId": "",
          "directionId": "UNSPECIFIED",
          "routeId": "",
          "stopId": "4062",
          "tripId": ""
        }
      ],
      "consequenceMessage": "",
      "consequences": [],
      "publicationWindows": [],
      "reason": "UNKNOWN_CAUSE",
      "severity": "noImpact",
      "summary": {
        "value": "Stop alert without arrivals",
        "lang": "en"
      }
    }
  ]
}

Author checklist

  • go vet -tags "sqlite_fts5 sqlite_math_functions" ./... passes
  • go vet -tags "purego" ./... passes
  • make test passes
  • go fmt ./... was run and its changes committed
  • Each commit is one logical change with a clear message (subject ≤50 chars, capitalized)
  • No hand-edits under gtfsdb/ (generated by sqlc)
  • Handlers pass r.Context() to DB/service calls, not context.Background()
  • SonarCloud cognitive-complexity check is passing (confirm once CI runs)
  • New branches/conditions have test coverage

Summary by CodeRabbit

  • Bug Fixes
    • Stop-scoped alerts are now included in location arrival results, including when no arrivals are available. The results include agency-qualified alert identifiers and corresponding situation details, so alerts remain linked and referenceable.

@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: ab51c363-432a-4f4b-90f5-54a355342de6
📥 Commits

Reviewing files that changed from the base of the PR and between 45b2deb and 308f031.

📒 Files selected for processing (2)
  • internal/restapi/arrivals_and_departures_for_location_handler_test.go
  • internal/restapi/arrivals_core.go

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

arrivalsForStops now collects stop alerts when a query has no arrivals and when arrivals exist. A test verifies that a stop alert appears in the response and that its situation reference resolves.

Changes: Stop alerts for quiet arrival windows

Layer / File(s) Summary
Collect alerts and verify quiet-window responses
internal/restapi/arrivals_core.go, internal/restapi/arrivals_and_departures_for_location_handler_test.go
arrivalsForStops collects alerts before returning an empty result and uses a helper that checks for context cancellation during per-stop collection. The test confirms the alert ID appears in SituationIDs and resolves in References.Situations when there are no arrivals.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: arcoder181105

Merge Risk: ⚪ Minimal · up to 308f0

The quiet-window response retains the stop alert and its situation reference. No actionable merge risk is established.

Pre-merge checks · Passed 4 · Failed 1

Failed Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks (4 passed)
Check name Status Explanation
Title check Passed The title clearly and concisely describes the primary fix: preserving stop alerts when location arrivals are empty.
Description check Passed The description explains the problem, root cause, implementation, testing, response behavior, and scope. It uses alternate section headings and does not reproduce every repository checklist item, but …
Linked Issues check Passed The description references issue #1565, and the implementation directly addresses its stated requirement to preserve stop-level alerts when no arrivals exist.
Out of Scope Changes check Passed The changes are limited to the batched arrivals logic and its regression test. They match the stated objective and do not include unrelated behavior changes.
  • Fix all pre-merge checks with AI
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Ahmedhossamdev

Copy link
Copy Markdown
Member

Looks good. Checked against Java StopWithArrivalsAndDeparturesBeanServiceImpl (stop alerts are collected per requested stop regardless of arrivals), and the new test fails on main with an assertion and passes here. The single caller is the location handler, and the early return calls the helper exactly once, so no duplicate situations.

Two optional notes: the manual loop at the end of the new test could be slices.ContainsFunc, and since this changes a Java-served response, a before/after JSON from a quiet query would complete the Response comparison section.

Separately (not for this PR): Java also adds route alerts for scheduled routes at the end of that method even with no arrivals; worth checking whether Maglev's batched path does the same.

@SurajSingh563

SurajSingh563 commented Oct 11, 2026 •

Copy link
Copy Markdown
Author

Thanks for the review @Ahmedhossamdev and for checking it against the Java implementation.

  • Switched the test's manual loop to slices.ContainsFunc (45b2deb).
  • Added a Maglev before/after JSON for a quiet query to the description under Response comparison. I don't have a Java server, so there is no Java side-by-side.
  • Agreed the route-alert behavior is out of scope here. I can look into whether the batched path adds route alerts for scheduled routes as a follow-up issue if that's useful.

@aaronbrethorst aaronbrethorst left a comment

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.

Thanks @SurajSingh563, the fix itself looks right to me. Collecting alerts for every stop in in.Stops matches Java, which adds each found stop's alerts inside its per-stop loop before anything is trimmed and whether or not the stop has arrivals (StopWithArrivalsAndDeparturesBeanServiceImpl.java#L112-L136). I also confirmed the new test fails against main's arrivals_core.go and passes here.

There's one thing to fix before this can merge. Commit 546cb42 has a Co-authored-by: Copilot trailer, and CONTRIBUTING asks that commits not be attributed to coding agents. That commit's body is also the first sentence split across a blank line ("…contains no" / "stop times, …"). Please reword that commit to remove the trailer and give it a proper body, then force-push. Rewriting history is fine here because removing the trailer requires it.

  • #1557 also edits this loop, but it scopes stop alerts to the stops left after trimming, and that doesn't match Java. Your version is the one that does.

arrivalsForStops returned early when no stop had a stop time in the
window, before stop-level alerts were collected, so quiet location
searches lost their situation references. Collect stop alerts for every
found stop before returning, matching Java. Fixes OneBusAway#1565.
@SurajSingh563
SurajSingh563 force-pushed the fix/1565-location-arrivals-stop-alerts branch 2 times, most recently from 45b2deb to 308f031 Compare October 13, 2026 17:18
@sonarqubecloud

Copy link
Copy Markdown

@SurajSingh563

Copy link
Copy Markdown
Author

Thanks, @aaronbrethorst . Done:

Reworded the commits to remove the Co-authored-by trailer, with a proper body on the first commit.
Rebased onto main and resolved the conflict with #1593; stop alerts are still collected for every stop in in.Stops.

Force-pushed. hope you will re-review thanks a lot

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.

Location arrivals drop stop alerts when no arrivals

3 participants