From the 2026-07-16 debt review (finding 8). Severity: medium.
Three related smells introduced by #1865/#1893:
-
stops-for-route via two independent repository paths. FocusedTripRepository.getStops uses RouteStopsDataSource.stopsForRoute with its own routeStopCache (FocusedTripRepository.kt:124-125,190-194), while RouteMapRepository.getRoute hits the same wire endpoint uncached via MapDataSource.routeMap (MapDataSource.kt:72-73), into a different model shape (RouteStopGroup vs RouteMapStop); RouteInfoRepository is a third consumer. "Focus a stop, then select one of its routes" fetches stops-for-route twice with no coalescing, and the two projections can come from different fetches. Refactor: one caching stops-for-route repository both project from. (medium)
-
Shape geometry double-cached under the same shapeId with divergent policies. TripObservationRepository's ShapeCache (Polyline, LRU 100, no TTL) vs FocusedTripRepository.shapeCache (List<GeoPoint>, LRU 32, 10-min TTL — FocusedTripRepository.kt:71-73,126-127,209-219). ~2x memory per focused shape, two eviction policies, and the 10-minute TTL on effectively immutable GTFS data is an unexplained freshness threshold (contrast MAX_CACHED_SHAPES, which carries a full rationale). Drop or document the TTL. (small)
-
The focused-trip set has three copies with scattered manual resets. ArrivalsRepository.lastGood.loaded.focusedTrips (ArrivalsRepository.kt:486-492) → HomeViewModel.focusedTrips, a plain var (HomeViewModel.kt:155) reset imperatively at four sites (175, 363, 471, 545) → RouteMapController.stopFocusSession.trips. Deriving the set from the focus state flow removes the "forgot to clear on transition X" bug class. (medium)
From the 2026-07-16 debt review (finding 8). Severity: medium.
Three related smells introduced by #1865/#1893:
stops-for-route via two independent repository paths.
FocusedTripRepository.getStopsusesRouteStopsDataSource.stopsForRoutewith its ownrouteStopCache(FocusedTripRepository.kt:124-125,190-194), whileRouteMapRepository.getRoutehits the same wire endpoint uncached viaMapDataSource.routeMap(MapDataSource.kt:72-73), into a different model shape (RouteStopGroupvsRouteMapStop);RouteInfoRepositoryis a third consumer. "Focus a stop, then select one of its routes" fetches stops-for-route twice with no coalescing, and the two projections can come from different fetches. Refactor: one caching stops-for-route repository both project from. (medium)Shape geometry double-cached under the same shapeId with divergent policies.
TripObservationRepository'sShapeCache(Polyline, LRU 100, no TTL) vsFocusedTripRepository.shapeCache(List<GeoPoint>, LRU 32, 10-min TTL —FocusedTripRepository.kt:71-73,126-127,209-219). ~2x memory per focused shape, two eviction policies, and the 10-minute TTL on effectively immutable GTFS data is an unexplained freshness threshold (contrastMAX_CACHED_SHAPES, which carries a full rationale). Drop or document the TTL. (small)The focused-trip set has three copies with scattered manual resets.
ArrivalsRepository.lastGood.loaded.focusedTrips(ArrivalsRepository.kt:486-492) →HomeViewModel.focusedTrips, a plainvar(HomeViewModel.kt:155) reset imperatively at four sites (175, 363, 471, 545) →RouteMapController.stopFocusSession.trips. Deriving the set from the focus state flow removes the "forgot to clear on transition X" bug class. (medium)