Skip to content

Fall back to tripStatus deviation for arrival prediction - #1460

Open
Ahmedhossamdev wants to merge 1 commit into
mainfrom
fix/1456-predicted-flag-from-trip-status
Open

Ahmedhossamdev wants to merge 1 commit into
mainfrom
fix/1456-predicted-flag-from-trip-status

Conversation

@Ahmedhossamdev

@Ahmedhossamdev Ahmedhossamdev commented Sep 19, 2026

Copy link
Copy Markdown
Member

Fixes: #1456

Bug

The same response could disagree with itself. tripStatus.predicted said true and tripStatus.scheduleDeviation was populated, but the arrival's own predicted field said false with predictedArrivalTime=0. Java doesn't do this: it uses one flag for both.

Concrete case from the issue, stop 1_1013, trip 1_2008464:

Field Java Maglev before
tripStatus.predicted true true
tripStatus.scheduleDeviation 174 174
predicted (top-level) true false
predictedArrivalTime schedArr + 174s 0

A client filtering on arrival.predicted treated a real-time-tracked bus as schedule-only. A client relying on predictedArrivalTime > 0 fell back to the scheduled time even though the deviation was right there on the same object.

Why

Two independent code paths were computing "is this predicted":

  • getPredictedTimes (per-stop): true only if the TripUpdate has an STU for this stop, an earlier stop, or a trip-level Delay.
  • BuildTripStatus (whole-trip): true whenever any real-time signal exists (fresh vehicle OR any StopTimeUpdate anywhere in the block).

For HART trips whose TripUpdates only carry per-stop entries for stops past the queried one, BuildTripStatus still resolved a ScheduleDeviation via its closest-in-time STU fallback, but getPredictedTimes returned false. The response then contradicted itself.

Java uses one signal for both: blockLocation.isPredicted() drives the arrival's predicted flag, and setPredictedTimesFromScheduleDeviation fills the predicted times as scheduled + deviation when the per-stop path (setPredictedTimesFromTimepointPredictionRecords) fails. See ArrivalsAndDeparturesBeanServiceImpl.applyBlockLocationToBean and ArrivalAndDepartureServiceImpl.setPredictedTimesFromScheduleDeviation.

Fix

Add a fallback in both handlers: when getPredictedTimes returns false but tripStatus.Predicted is true, mark the arrival predicted and set predicted times to scheduled + tripStatus.ScheduleDeviation.

  • New helper predictedTimesFromTripStatus in trips_helper.go.
  • Wired into buildArrival in arrivals_core.go (plural handler) and the singular handler.
  • Two existing tests codified the old strict behavior (TestPluralArrivals_NoMatchingOrPriorStop, TestPluralArrivals_VehiclePositionAloneDoesNotPredict); flipped both to assert the new behavior.
  • Added two _DownstreamOnlySTUPredictsFromDeviation tests (one per handler) that reproduce the exact issue scenario.

Verification

Live diff against Tampa hosted Java (same HART feed) for stop 1_1013:

  • Before: predicted=false, predictedArrivalTime=0 on the three tracked trips at that stop.
  • After (locally rebuilt): predicted=true, predictedArrivalTime=scheduled+deviation, matching Java.

Summary by CodeRabbit

  • Bug Fixes
    • Arrival and departure predictions now remain available when real-time updates only affect downstream stops.
    • Schedule deviations are applied consistently to calculate predicted times.
    • Vehicle-position updates can now provide schedule-based predictions when no explicit prediction is available.
    • Existing arrival and departure values are preserved when no valid fallback prediction can be calculated.

@coderabbitai

coderabbitai Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

Warning

Review limit reached

Next included review available in 52 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 1ff6c263-02ba-438d-b677-b0d28c6ad4e3

📥 Commits

Reviewing files that changed from the base of the PR and between 6c54353 and d736bb1.

📒 Files selected for processing (3)
  • internal/restapi/arrival_and_departure_for_stop_handler.go
  • internal/restapi/arrival_and_departure_for_stop_handler_test.go
  • internal/restapi/arrivals_and_departures_for_stop_handler_test.go

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: 6d1a3831-dac5-490e-80f1-1cc27e57f0a0

📥 Commits

Reviewing files that changed from the base of the PR and between 467aa83 and 6c54353.

📒 Files selected for processing (5)
  • internal/restapi/arrival_and_departure_for_stop_handler.go
  • internal/restapi/arrival_and_departure_for_stop_handler_test.go
  • internal/restapi/arrivals_and_departures_for_stop_handler_test.go
  • internal/restapi/arrivals_core.go
  • internal/restapi/trips_helper.go

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


📝 Walkthrough

Walkthrough

The arrival endpoints now use predicted trip-status schedule deviation when direct stop-time predictions are unavailable. The change updates singular and plural endpoint tests for vehicle-position and downstream-only TripUpdate scenarios.

Changes

Arrival prediction fallback

Layer / File(s) Summary
Trip-status fallback implementation
internal/restapi/trips_helper.go, internal/restapi/arrivals_core.go, internal/restapi/arrival_and_departure_for_stop_handler.go
Adds schedule-deviation-based predicted times and applies them when direct prediction lookup returns no times.
Fallback behavior validation
internal/restapi/arrivals_and_departures_for_stop_handler_test.go, internal/restapi/arrival_and_departure_for_stop_handler_test.go
Updates plural endpoint expectations and adds singular and plural coverage for vehicle-position and downstream-only TripUpdate data.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: arcoder181105

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ArrivalEndpoint
  participant PredictionLookup
  participant TripStatus
  Client->>ArrivalEndpoint: request arrival data
  ArrivalEndpoint->>PredictionLookup: retrieve direct predicted times
  PredictionLookup-->>ArrivalEndpoint: no per-stop prediction
  ArrivalEndpoint->>TripStatus: read predicted status and schedule deviation
  TripStatus-->>ArrivalEndpoint: return schedule deviation
  ArrivalEndpoint-->>Client: return predicted arrival and departure times
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: using tripStatus deviation as a fallback for arrival prediction.
Linked Issues check ✅ Passed The PR meets the coding requirements in [#1456]. predictedTimesFromTripStatus returns scheduled arrival and departure times plus TripStatus.ScheduleDeviation when TripStatus.Predicted is true. B…
Out of Scope Changes check ✅ Passed The changed production files implement the [#1456] fallback. The changed test files update the affected expectation and add coverage for both endpoints. The changes stay within the linked issue scope.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch fix/1456-predicted-flag-from-trip-status

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.

The arrival-level `predicted` flag was derived only from getPredictedTimes,
which requires a TripUpdate with a per-stop entry matching the queried stop,
an earlier stop, or a trip-level Delay. BuildTripStatus already treats a
trip as predicted whenever any real-time signal exists (fresh vehicle or
any real-time source in the block). When the two paths disagreed, the same
response would report `tripStatus.predicted=true` and `arrival.predicted=
false` with `predictedArrivalTime=0`, contradicting Java.

Add a fallback that runs after getPredictedTimes misses: if
tripStatus.Predicted is set, mark the arrival predicted and use
scheduledTime + tripStatus.ScheduleDeviation as the predicted time. This
mirrors Java's setPredictedTimesFromScheduleDeviation, which runs when
setPredictedTimesFromTimepointPredictionRecords fails.

Flip two tests that codified the old strict behavior and add coverage for
a TripUpdate whose only StopTimeUpdate targets a downstream stop.
@Ahmedhossamdev
Ahmedhossamdev force-pushed the fix/1456-predicted-flag-from-trip-status branch from 6c54353 to d736bb1 Compare September 19, 2026 03:21
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

Performance Smoke Test Results

Status: PASSED

Metric Value
p(95) latency 1.9 ms
Error rate 0.00%
Total requests 337
Req/sec 11.1

Smoke test config: 5 VUs x 30s. Thresholds: p(95) < 300ms, error rate < 1%.

Full results uploaded as workflow artifact: k6-smoke-summary.

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.

arrival-and-departure endpoints: predicted flag stays false when trip has real-time data

1 participant