Every defect the hackathon solutions hit, deduplicated, routed to a repo, and
written paste-ready. Sources are the per-solution docs in this folder plus
docs/busanalysis.md.
Nothing here has been filed yet. This is the prep.
Most of these are not open-bus-map-search bugs. That repo is the React
frontend; the defects are in the API, the DB and the ETL. But it is the most
active repo, it has data research and bus-expert-needed labels, and — crucially
— it is a consumer of the broken fields, so several of these have a real
frontend-visible symptom that belongs there.
The split used below:
| Repo | Gets |
|---|---|
| open-bus-map-search | Symptoms visible in the UI, and requests to surface data caveats to users |
| open-bus-stride-api | Endpoint behaviour: ignored filters, error codes, undocumented limits, field semantics |
| open-bus-stride-db | Data content: null columns, duplicate rows, coverage holes |
| open-bus-pipelines | ETL jobs that stopped or import wrongly |
Useful labels on map-search: data research, bus-expert-needed, backend,
timezone/midnight, clarification needed.
Searched all four repos. What already exists:
| Existing | State | Our relationship to it |
|---|---|---|
| stride-api#49 — "API returns total_actual_rides: 0 for all operators on 2025-09-17 !" | open, 0 comments, filed 2025-09-18 | Same defect as our A. One date; we have 9 months, network-wide, plus a control. Comment, do not open a new issue. |
| stride-api#23 — "stride.get doesn't filter on line_ref and operator_ref" | closed | Same family as our B (a filter accepted and not applied) on /siri_rides/list. Ours is /siri_vehicle_locations/list and gtfs_route__route_short_name. Reference it; it suggests a recurring class of bug. |
stride-api#54 — "rides_execution/list uses UTC midnight for date filtering instead of Israel midnight" |
closed | Explains orion's "the API's service-date filter is fuzzy at the window edges". Verify whether the fix shipped before filing anything on it — our client-side re-filter may now be unnecessary. |
| stride-api#43 — "Missing data" | open, 3 comments | Possibly a broad umbrella for several of these. Read before filing. |
| map-search#1149 | open | rides_execution/list returns empty without certain parameters. Adjacent to our E. |
| map-search#19 — "Improve rides reliability metric by adding 'actual start time' ETL" | open | Directly relevant to our E and G. |
| map-search#175 — "Research | explain weird patterns in the data" | open | Several findings here are candidate answers. |
hasadna issue #390 — scheduled_start_time drift |
referenced by BusAnalysis F6 | Root cause of our D. Locate it before filing D. |
No existing issue found for: the ignored route_short_name filter on
siri_vehicle_locations, the SIRI reporting-lead-time artifact, duplicate ping
rows, the >15k row cap, or the schedualed misspelling.
Action: comment on stride-api#49, don't open a new issue. Then open the map-search issue below, because this one has a live UI symptom.
Evidence to add to #49:
Confirming this is not specific to 2025-09-17. Two independent hackathon analyses measured it across
/gtfs_rides_agg/listand/group_by, on every date sampled from 2025-11 to 2026-07, network-wide:
Date Σ planned Σ actual 2026-07-01 3,498 0 2026-06-15 3,510 0 2026-04-01 3,227 0 2025-11-01 3,927 0 It is not ingestion lag. Control: line 2259 on 2026-07-29 reports
total_actual_rides=0in the aggregate, while/rides_execution/listfor the same line and date returns realactual_start_timevalues and zero cancellations. Actuals exist at ride level and are not being rolled into the aggregate.
num_planned_ridesis populated normally and cross-checks well against the ride-level endpoint (aggregate 123 vs 126 planned for that line/date), so the aggregate is usable as a planned-ride denominator — the actual column alone is the problem.Sources: orion's method study, service_violations.py.
Repo: open-bus-map-search · Labels: bug, data research, bus-expert-needed
Title: Dashboard charts show ~0% actual rides because
total_actual_ridesis unpopulated upstream
totalActualRidesis consumed in five places:
src/pages/dashboard/AllLineschart/AllLinesChart.tsxsrc/pages/dashboard/WorstLinesChart/WorstLinesChart.tsxsrc/pages/dashboard/ArrivalByTimeChart/DayTimeChart.tsxsrc/pages/operator/OperatorGaps.tsxsrc/pages/DataResearch/DataResearch.tsxall fed by
useGroupBy→/gtfs_rides_agg/group_by(src/api/groupByService.ts).That column is 0 for every row network-wide (upstream: hasadna/open-bus-stride-api#49). The rendered result is not "no data" — it is a confident chart showing that essentially no bus in Israel ran.
Until the upstream column is fixed, the frontend should detect
totalActualRides === 0 && totalPlannedRides > 0across a whole response and show a data-quality banner rather than plotting it.Reproduced independently by two hackathon analyses; see the evidence table in hasadna/open-bus-stride-api#49.
Why this is the highest-priority item: it is the only defect here with a confirmed, currently-live, user-facing wrong answer in hasadna's own product.
Repo: open-bus-stride-api · Labels: bug
Source: route-divergence.md finding 1, gps-trace-map.md finding 1
Title:
/siri_vehicle_locations/listacceptsgtfs_route__route_short_nameand ignores it, returning the entire country's pingsPassing
gtfs_route__route_short_nameto/siri_vehicle_locations/listdoes not filter. It does not error, does not warn, and does not return an empty set — it returns every ping in the time window, from every line in the country. The caller then treats them as belonging to their line.This is how we caught it: an off-route analysis reported buses 50 km from their route on 97.7% of pings. The buses were fine; the pings belonged to other lines.
The symptom is only obvious because that particular analysis produces an absurd number. Anything computing a rate, a median or a coverage percentage gets a plausible, wrong answer with no indication anything went wrong.
Two separate hackathon participants hit this independently. The working filter is
siri_routes__line_ref(aline_ref, not aroute_short_name), which requires resolving through/gtfs_routes/listfirst.Requested: either apply the filter, or reject the parameter with a 4xx. Silently ignoring a filter is the worst of the three options.
Possibly the same class of bug as #23 (closed), which was
/siri_rides/listnot joining online_ref/operator_ref.
Repo: open-bus-pipelines (job) + open-bus-stride-db (symptom)
Labels: bug · Source: service-violations.md finding 3, BusAnalysis F1 + F7
Title: The SIRI→GTFS ride-matching job has written no matches since 2024-10;
first_vehicle_location_idnull for 18 monthsTwo related symptoms, both observed independently by two projects:
1. The ride link.
siri_ride.gtfs_ride_idand its three siblings (route_gtfs_ride_id,scheduled_time_gtfs_ride_id,journey_gtfs_ride_id) all stop being populated together. Healthy through 2024-08, degrading 2024-09, effectively zero 2024-10 → 2026-07. The raw feed never stopped: ~2.9–3.1Msiri_riderows/month are still created.2. The enrichment.
siri_ride.first_vehicle_location_idis null for 100.00% of rides for 18 consecutive months (2024-12 → 2026-05, 49.4M rides);duration_minutestracks it to within 0.006/month. Overall 49.21% of allsiri_riderows have it null.A hackathon analysis independently found these columns "inconsistently NULL — present for some days, absent for others, for identical, genuinely-tracked rides", and had to derive planned-vs-actual from raw GPS pings instead.
The interpretation risk on (2) is worth calling out separately:
first_vehicle_location_idlooks like it means "this vehicle never reported its position", and it is easy to build a per-operator transmission metric on it. It does not mean that — it encodes whether the enrichment job has processed that day. It is a processing-state flag, not a property of the bus.Detail and day-by-day scans: BusAnalysis
handoff/issues/F1-stored-linkage.mdandF7-enrichment-flag.md(private repo; ask @lihay7 to share).
Repo: open-bus-stride-db · Labels: bug, data research
Source: BusAnalysis F6, days-with-no-cancellations.md finding 5, repo-wide ~10% duplicate ping rate
Title: 2.6% of
siri_riderows are duplicate journeys; overlapping snapshots also repeat ~10% of location rowsRide level. Over a full census (2022-12-30 → 2026-08-01, 116,335,248 rows): 3.93% of rides sit in a duplicated
(siri_route_id, journey_ref, service day)group, 2.56% of all rows are surplus duplicates, 66× skewed across operators, and the rate has roughly quadrupled from 2023 to 2026. Downstream of thescheduled_start_timedrift bug (hasadna #390): when a journey's scheduled start drifts, a new row is written instead of the existing one being updated.The same shape appears in GTFS. 2026-07-26 on one line returned 259
/rides_execution/listrows for 127 distinctplanned_start_times (some ×4) under 255 distinctgtfs_ride_ids — one physical departure emitted under several ride ids. Any naive count of planned rides double-counts, and a duplicated row with a null actual becomes a phantom cancellation.Location level. Overlapping SIRI snapshots repeat the same physical observation — same
siri_ride__id, samerecorded_at_time, same lat/lon — at roughly 10% of rows. Harmless formin()/max()aggregations, not harmless for anything weighted or counted: one hackathon analysis computes a distance-weighted average position, where a duplicated ping carries its weight twice.Every analysis in our hackathon repo now dedups on
(siri_ride__id, recorded_at_time, lat, lon)as a matter of course. That is a workaround every consumer is independently reinventing.
Repo: open-bus-stride-api · Labels: documentation, data research
Source: days-with-no-cancellations.md finding 2
Title:
rides_execution.actual_start_timealways equalsplanned_start_time— document it as a boolean, or populate itFor all 1,726 non-null rows sampled,
actual_start_time == planned_start_timeto the second.The field is genuinely useful as-is: null means the ride did not run, which is the cleanest cancellation signal in the API, and we built a working days-without-cancellations score on it. But the name promises an observed departure time, and it is not one. The endpoint can never be used for delay or punctuality work.
Requested: either populate it from SIRI, or rename/document it as
did_run-style boolean so nobody builds a punctuality metric on it. Related: hasadna/open-bus-map-search#19.
Repo: open-bus-map-search (data research) and/or open-bus-stride-db (documentation)
Source: service-violations.md finding 1 — the most reusable result the hackathon produced
Title: "First SIRI ping" is not departure time — the feed reports a vehicle ~30 or ~5 min before its scheduled start, while stationary
On a sampled line, ~80% of rides' raw first pings landed at almost exactly −30 or −5 minutes before scheduled departure, with
distance_from_journey_start == 0andvelocity == 0— the vehicle parked at the origin stop, boarding.Taking that first ping as "actual departure" made ~90% of matched rides look early. That is not early running; it is the operator feed's reporting lead time.
Two sharp clusters at fixed offsets rather than a smooth distribution is what identifies it as a feed convention.
The fix that worked: use the first ping where the vehicle has actually started moving —
distance_from_journey_start > 0 || velocity > 0— and fall back to the raw first ping only when the vehicle was never observed moving (and flag those rides as unreliable).Filing this as documentation/research rather than a bug: the feed is behaving as operators report it. But any consumer computing departure punctuality from first-ping is currently measuring the wrong thing, and there is nothing in the docs that says so.
Repo: open-bus-stride-api · Labels: documentation
Source: siri-coverage.md findings 1–3, bus-bunching.md finding 2
Title: Document (or make discoverable) four hard endpoint constraints that are currently found by trial and error
Every hackathon participant rediscovered these independently. None is in the OpenAPI docs.
/route_timetable/listrejects any date range over a single day, and times out server-side when unfiltered regardless of range./siri_vehicle_locations/listaccepts only oneline_refper request, while/route_timetable/list'sline_refsdoes accept a comma-separated batch. The asymmetry is surprising and undocumented.- There is a row cap between 15,000 and 20,000.
limit=15000succeeds;limit=20000returns an immediate 500. A 400 with a stated maximum, or a documented cap, would save everyone the bisection.stride.iterate()'slimit=kwarg is client-side only — the server silently defaults to ~100 rows unlesslimitis also passed inside the request params. This one is the most dangerous: it is a silent truncation, not an error, so an analysis that doesn't know gets a plausible answer computed from the first 100 rows.Happy to open a PR against the docs if that's the preferred route.
Repo: open-bus-stride-api · Labels: bug, good first issue
Title: Passing a naive datetime to time-range filters returns 500 ("tzinfo is required") instead of a 4xx
/siri_vehicle_locations/listand/route_timetable/list500 with "tzinfo is required" when a time filter is given without a timezone. This is a client input error and should be a 422 with the field named. It is currently indistinguishable from a server fault, and every analysis in our repo carries a_day_bounds()helper written specifically to avoid it.
Repo: open-bus-stride-api · Labels: good first issue
Title:
siri_rides__schedualed_start_time_from/tois misspelled ("schedualed")Every consumer carries a
# siccomment next to it. Suggest acceptingscheduled_start_time_from/toas an alias, keeping the old spelling working, and marking it deprecated in the docs. Cheap, and it stops propagating the typo into every downstream codebase.
Repo: open-bus-stride-db · Labels: data research
A real minority of
/gtfs_rides/listrows return withstart_time(andend_time) null. A ride with no scheduled time cannot be timed or ghost-checked; left in a planned-vs-actual join it falls through as a spurious unmatched "cancellation". Looks like a GTFS source gap rather than a SIRI matching problem. Worth quantifying network-wide — we only have per-query counts.
Repo: open-bus-stride-db + open-bus-map-search · Source: BusAnalysis F9, corroborated by siri-coverage.md finding 7
Three operators are never present in SIRI across 2023-01 → 2026-07, and two more are under 1% covered. Together: 2.74M scheduled rides, ~2.3% of national planned volume.
Their buses may be running perfectly. Nothing reports them, so nothing about them can be measured — and counting them as cancellations is most of how a national non-execution figure goes from 5.2% to 7.4%.
For map-search: these operators should be visibly marked as unmeasured rather than appearing in reliability rankings with a terrible score.
Repo: open-bus-pipelines · Source: BusAnalysis F8
On affected dates
gtfs_rideholds two near-complete daily schedules under a singlegtfs_route.date— same trip, same route row, samestart_time, withjourney_refsuffixes stamping both the current and previous release. 85% of days are clean; 50 days exceed 1.5× the expected planned count and 36 exceed 1.8×, scattered across 2023-02 → 2026-07 with no era pattern.Planned-ride denominators are ~2× too high on those dates.
- A + A2 — live wrong answer in hasadna's own UI. A is a comment on an existing issue, A2 is new. Do these first.
- B — silent wrong results, trivially reproducible, two independent hits.
- G, H, I — cheap documentation/DX wins that build credibility before the heavier data issues.
- C, D — the big ETL ones. Both need BusAnalysis's census numbers, which means asking @lihay7 to share or re-derive them; do not cite a private repo's figures publicly without asking first.
- E, F — semantics and interpretation; frame as research, not bug reports.
- J, K, L — quantify further before filing.
- Confirm with the original authors (noamf2001, yuvalko1, orion, @lihay7) that they're happy to be credited, and how.
- Get @lihay7's permission before quoting BusAnalysis figures — the repo is private.
- Re-verify each finding against the live API on filing day. Several date windows here are hackathon-specific, and stride-api#54 shows fixes do ship.
- Read stride-api#43 ("Missing data") and map-search#175 ("explain weird patterns in the data") — some of these may belong as comments there rather than as new issues.
- Replace the
(…)source placeholders in draft A with real permalinks once this repo is public at its new home (hasadna/open-bus-hackathon-26).