Add implementation code for all 4 improvement plan phases

Production changes:
- TravelEstimator: remove 300mi fallback, return nil on missing coords
- TripPlanningEngine: add warnings array, empty sports warning, inverted
  date range rejection, must-stop filter, segment validation gate
- GameDAGRouter: add routePreference parameter with preference-aware
  bucket ordering and sorting in selectDiverseRoutes()
- ScenarioA-E: pass routePreference through to GameDAGRouter
- ScenarioA: track games with missing stadium data
- ScenarioE: add region filtering for home games
- TravelSegment: add requiresOvernightStop and travelDays() helpers

Test changes:
- GameDAGRouterTests: +252 lines for route preference verification
- TripPlanningEngineTests: +153 lines for segment validation, date range,
  empty sports
- ScenarioEPlannerTests: +119 lines for region filter tests
- TravelEstimatorTests: remove obsolete fallback distance tests
- ItineraryBuilderTests: update nil-coords test expectation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey T
2026-03-21 09:40:32 -05:00
parent db6ab2f923
commit 6cbcef47ae
14 changed files with 807 additions and 88 deletions

View File

@@ -58,6 +58,17 @@ struct TravelSegment: Identifiable, Codable, Hashable {
var estimatedDrivingHours: Double { durationHours }
var estimatedDistanceMiles: Double { distanceMiles }
/// Whether this segment requires an overnight stop based on driving time.
/// Segments over 8 hours of driving require rest.
var requiresOvernightStop: Bool {
durationHours > 8.0
}
/// Number of travel days this segment spans (accounting for daily driving limits).
func travelDays(maxDailyHours: Double = 8.0) -> Int {
max(1, Int(ceil(durationHours / maxDailyHours)))
}
var formattedDistance: String {
String(format: "%.0f mi", distanceMiles)
}