Skip to content

Issue #474: Fix -1 no-prediction sentinel corrupted into a bogus pred… - #475

Open
JRroony wants to merge 1 commit into
OneBusAway:mainfrom
JRroony:fix/issue-474-sentinel-arithmetic
Open

Issue #474: Fix -1 no-prediction sentinel corrupted into a bogus pred…#475
JRroony wants to merge 1 commit into
OneBusAway:mainfrom
JRroony:fix/issue-474-sentinel-arithmetic

Conversation

@JRroony

@JRroony JRroony commented Aug 4, 2026

Copy link
Copy Markdown

Summary

TimepointPredictionRecord uses -1 to represent a missing realtime prediction. When a matching record contained neither a valid arrival nor departure prediction, ArrivalAndDepartureServiceImpl added the stop slack to the -1 arrival sentinel. For a stop with 30 seconds of slack, this produced 29999, which was then exposed through the API as a genuine predicted timestamp near the Unix epoch.

This caused clients to display invalid arrival information, including an Android ETA of approximately -496,000 hours. This change prevents arithmetic on the no-prediction sentinel while preserving the existing behavior for valid partial predictions.

Fixes #474

Changes

  • Only synthesize a predicted departure as arrival + slack when the arrival prediction is a valid positive timestamp.
  • Normalize the no-arrival/no-departure case to 0, the no-prediction value used by the arrival/departure service and API.
  • Preserve the existing partial-prediction behavior:
    • When only an arrival prediction is available, derive the departure using stop slack.
    • When only a departure prediction is available, use it as the arrival fallback.
  • Prevent absent or cleared predictions from overwriting computed scheduled times for frequency-based trips.
  • Fix hasPredictedDepartureTime() in the V1 and V2 arrival/departure beans to check predictedDepartureTime instead of predictedArrivalTime.
  • Add regression coverage for missing, arrival-only, and departure-only predictions, frequency-based schedules, API-facing bean output, and V1/V2 best-departure selection.

Test plan

  • Ran the affected-module Maven verification on JDK 11:

    mvn -pl onebusaway-api-core,onebusaway-api-webapp,onebusaway-transit-data-federation -am verify -Dgpg.skip=true

    All 17 selected modules and dependencies completed with BUILD SUCCESS.

  • Verified the four directly affected test classes: 34 tests passed with 0 failures, 0 errors, and 0 skipped.

    • ArrivalAndDepartureServiceImplTest: 25 tests
    • ArrivalsAndDeparturesBeanServiceImplTest: 5 tests
    • ArrivalAndDepartureBeanV1Test: 2 tests
    • ArrivalAndDepartureV2BeanTest: 2 tests
  • git diff --check

Summary by CodeRabbit

  • Bug Fixes

    • Corrected predicted departure detection in arrival and departure responses.
    • Improved handling of missing or invalid realtime predictions without generating misleading times.
    • Preserved scheduled frequency-based arrival and departure times when predictions are unavailable.
    • Improved fallback calculations when only an arrival or departure prediction is provided.
  • Tests

    • Added regression coverage for missing, partial, and invalid realtime prediction scenarios across supported arrival APIs.

…bogus predicted time

TimepointPredictionRecord uses -1 to mean "no realtime prediction." When a
record had neither a real arrival nor departure (e.g. a SKIPPED stop, or a
dynamic/added trip update with no times populated), setPredictedTimes...
FromTimepointPredictionRecords computed departureTime = arrivalTime + slack,
turning -1 into slack*1000-1 (e.g. 29999ms). That value passes every
downstream "is this a real prediction" check and gets served to API
clients as if it were a genuine timestamp near the Unix epoch; one Android
client turned it into an ETA of roughly -496,000 hours.

- Only synthesize departureTime from arrivalTime when arrivalTime is a
  real prediction (> 0), and normalize any remaining non-positive time to
  this class's own "no prediction" sentinel (0) instead of leaking -1
  downstream, matching the convention already used by this method's
  existing "no match found" fallback and the public API's documented
  behavior for predictedArrivalTime/predictedDepartureTime.
- Guard the scheduled-time side effect in setPredictedArrivalTimeForInstance/
  setPredictedDepartureTimeForInstance so that clearing a prediction to 0
  no longer stomps a frequency-based trip's computed schedule (a latent bug
  that the above normalization would otherwise have newly triggered).
- Fix a related copy-paste bug where ArrivalAndDepartureBeanV1 and
  ArrivalAndDepartureV2Bean's hasPredictedDepartureTime() checked
  predictedArrivalTime instead of predictedDepartureTime.

Adds regression tests covering all arrival/departure combinations,
including the frequency-schedule interaction, plus unit tests for the
hasPredictedDepartureTime() fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 26873a21-6d8e-4fa8-9b5c-3a1c84019b17

📥 Commits

Reviewing files that changed from the base of the PR and between 07fd254 and 04f94eb.

📒 Files selected for processing (7)
  • onebusaway-api-core/src/main/java/org/onebusaway/api/model/transit/ArrivalAndDepartureV2Bean.java
  • onebusaway-api-core/src/test/java/org/onebusaway/api/model/transit/ArrivalAndDepartureV2BeanTest.java
  • onebusaway-api-webapp/src/main/java/org/onebusaway/api/model/where/ArrivalAndDepartureBeanV1.java
  • onebusaway-api-webapp/src/test/java/org/onebusaway/api/model/where/ArrivalAndDepartureBeanV1Test.java
  • onebusaway-transit-data-federation/src/main/java/org/onebusaway/transit_data_federation/impl/ArrivalAndDepartureServiceImpl.java
  • onebusaway-transit-data-federation/src/test/java/org/onebusaway/transit_data_federation/impl/ArrivalAndDepartureServiceImplTest.java
  • onebusaway-transit-data-federation/src/test/java/org/onebusaway/transit_data_federation/impl/beans/ArrivalsAndDeparturesBeanServiceImplTest.java

📝 Walkthrough

Walkthrough

The change corrects predicted departure detection in both API beans. It also normalizes missing realtime predictions in arrival processing and preserves frequency schedules. Regression tests cover API beans, timepoint predictions, frequency service results, and singular stop-arrival output.

Changes

Prediction time handling

Layer / File(s) Summary
API predicted departure detection and regression tests
onebusaway-api-core/src/main/..., onebusaway-api-webapp/src/main/...
Both API beans now check predicted departure timestamps directly. Tests cover missing predicted arrivals and missing predicted departures.
Arrival service prediction normalization
onebusaway-transit-data-federation/src/main/java/.../ArrivalAndDepartureServiceImpl.java, onebusaway-transit-data-federation/src/test/java/.../ArrivalAndDepartureServiceImplTest.java
The service keeps missing predictions at zero, uses departure as the arrival fallback when applicable, synthesizes departure only from positive arrival predictions, and preserves frequency-based schedules.
Singular stop-arrival output validation
onebusaway-transit-data-federation/src/test/java/.../beans/ArrivalsAndDeparturesBeanServiceImplTest.java
The test verifies zero predicted times and unchanged scheduled times when realtime predictions are unset.

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

Sequence Diagram(s)

sequenceDiagram
  participant TimepointPredictionRecord
  participant ArrivalAndDepartureServiceImpl
  participant ArrivalAndDepartureInstance
  TimepointPredictionRecord-->>ArrivalAndDepartureServiceImpl: predicted arrival and departure times
  ArrivalAndDepartureServiceImpl->>ArrivalAndDepartureServiceImpl: normalize missing predictions and apply stop slack
  ArrivalAndDepartureServiceImpl->>ArrivalAndDepartureInstance: set 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 75.00% which is insufficient. The required threshold is 80.00%. 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 identifies the fix for the -1 no-prediction sentinel described in the pull request.
Linked Issues check ✅ Passed The changes address issue #474 by preventing invalid sentinel arithmetic, preserving valid fallbacks, and adding regression tests.
Out of Scope Changes check ✅ Passed The bean corrections and regression tests support the prediction-handling objectives in issue #474.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

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.

Arithmetic on the -1 no-prediction sentinel emits slack*1000-1 as a predicted time

1 participant