feat: improve planning engine travel handling, itinerary reordering, and scenario planners

Add TravelInfo initializers and city normalization helpers to fix repeat
city-pair disambiguation. Improve drag-and-drop reordering with segment
index tracking and source-row-aware zone calculation. Enhance all five
scenario planners with better next-day departure handling and travel
segment placement. Add comprehensive tests across all planners.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-02-13 08:55:23 -06:00
parent 1c97f35754
commit 9736773475
19 changed files with 928 additions and 171 deletions

View File

@@ -272,6 +272,63 @@ struct ScenarioDPlannerTests {
#expect(!options.isEmpty)
}
@Test("plan: useHomeLocation with startLocation adds home start and end stops")
func plan_useHomeLocationWithStartLocation_addsHomeEndpoints() {
let startDate = Date()
let endDate = startDate.addingTimeInterval(86400 * 10)
let homeCoord = CLLocationCoordinate2D(latitude: 39.7392, longitude: -104.9903) // Denver
let homeLocation = LocationInput(name: "Denver", coordinate: homeCoord)
let bostonStadium = makeStadium(id: "boston", city: "Boston", coordinate: bostonCoord)
let game = Game(
id: "team-game",
homeTeamId: "red-sox",
awayTeamId: "yankees",
stadiumId: "boston",
dateTime: startDate.addingTimeInterval(86400 * 3),
sport: .mlb,
season: "2026",
isPlayoff: false
)
let prefs = TripPreferences(
planningMode: .followTeam,
startLocation: homeLocation,
sports: [.mlb],
startDate: startDate,
endDate: endDate,
leisureLevel: .moderate,
lodgingType: .hotel,
numberOfDrivers: 2,
followTeamId: "yankees",
useHomeLocation: true
)
let request = PlanningRequest(
preferences: prefs,
availableGames: [game],
teams: [:],
stadiums: ["boston": bostonStadium]
)
let result = planner.plan(request: request)
guard case .success(let options) = result else {
Issue.record("Expected success with home endpoint enabled")
return
}
#expect(!options.isEmpty)
for option in options {
#expect(option.stops.first?.city == "Denver")
#expect(option.stops.last?.city == "Denver")
#expect(option.stops.first?.games.isEmpty == true)
#expect(option.stops.last?.games.isEmpty == true)
}
}
// MARK: - Invariant Tests
@Test("Invariant: all returned games have team as home or away")