refactor: change domain model IDs from UUID to String canonical IDs

This refactor fixes the achievement system by using stable canonical string
IDs (e.g., "stadium_mlb_fenway_park") instead of random UUIDs. This ensures
stadium mappings for achievements are consistent across app launches and
CloudKit sync operations.

Changes:
- Stadium, Team, Game: id property changed from UUID to String
- Trip, TripStop, TripPreferences: updated to use String IDs for games/stadiums
- CKModels: removed UUID parsing, use canonical IDs directly
- AchievementEngine: now matches against canonical stadium IDs
- All test files updated to use String IDs instead of UUID()

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-01-12 09:24:33 -06:00
parent 4b2cacaeba
commit 1703ca5b0f
53 changed files with 642 additions and 727 deletions

View File

@@ -31,7 +31,7 @@ struct EdgeCaseTests {
/// Creates a stadium at a known location
private func makeStadium(
id: UUID = UUID(),
id: String = "stadium_test_\(UUID().uuidString)",
city: String,
state: String = "ST",
lat: Double,
@@ -52,10 +52,10 @@ struct EdgeCaseTests {
/// Creates a game at a stadium
private func makeGame(
id: UUID = UUID(),
stadiumId: UUID,
homeTeamId: UUID = UUID(),
awayTeamId: UUID = UUID(),
id: String = "game_test_\(UUID().uuidString)",
stadiumId: String,
homeTeamId: String = "team_test_\(UUID().uuidString)",
awayTeamId: String = "team_test_\(UUID().uuidString)",
dateTime: Date,
sport: Sport = .mlb
) -> Game {
@@ -75,7 +75,7 @@ struct EdgeCaseTests {
city: String,
state: String = "ST",
coordinate: CLLocationCoordinate2D? = nil,
games: [UUID] = [],
games: [String] = [],
arrivalDate: Date = Date()
) -> ItineraryStop {
ItineraryStop(
@@ -95,8 +95,8 @@ struct EdgeCaseTests {
@Test("11.1 - Nil stadium ID handled gracefully")
func test_nilStadium_HandlesGracefully() {
// Setup: Create games where stadium lookup would return nil
let validStadiumId = UUID()
let nonExistentStadiumId = UUID()
let validStadiumId = "stadium_valid_\(UUID().uuidString)"
let nonExistentStadiumId = "stadium_nonexistent_\(UUID().uuidString)"
let chicago = makeStadium(id: validStadiumId, city: "Chicago", lat: 41.8781, lon: -87.6298)
let stadiums = [validStadiumId: chicago]
@@ -133,7 +133,7 @@ struct EdgeCaseTests {
@Test("11.2 - Malformed date handled gracefully")
func test_malformedDate_HandlesGracefully() {
// Setup: Create games with dates at extremes
let stadiumId = UUID()
let stadiumId = "stadium_test_\(UUID().uuidString)"
let chicago = makeStadium(id: stadiumId, city: "Chicago", lat: 41.8781, lon: -87.6298)
let stadiums = [stadiumId: chicago]
@@ -172,9 +172,9 @@ struct EdgeCaseTests {
@Test("11.3 - Invalid coordinates handled gracefully")
func test_invalidCoordinates_HandlesGracefully() {
// Setup: Create stadiums with invalid coordinates
let validId = UUID()
let invalidLatId = UUID()
let invalidLonId = UUID()
let validId = "stadium_valid_\(UUID().uuidString)"
let invalidLatId = "stadium_invalidlat_\(UUID().uuidString)"
let invalidLonId = "stadium_invalidlon_\(UUID().uuidString)"
// Valid stadium
let validStadium = makeStadium(id: validId, city: "Chicago", lat: 41.8781, lon: -87.6298)
@@ -239,7 +239,7 @@ struct EdgeCaseTests {
@Test("11.4 - Missing required fields handled gracefully")
func test_missingRequiredFields_HandlesGracefully() {
// Setup: Test with empty games array
let stadiumId = UUID()
let stadiumId = "stadium_test_\(UUID().uuidString)"
let chicago = makeStadium(id: stadiumId, city: "Chicago", lat: 41.8781, lon: -87.6298)
let stadiums = [stadiumId: chicago]
@@ -258,7 +258,7 @@ struct EdgeCaseTests {
// Test with empty stadiums dictionary
let game = makeGame(stadiumId: stadiumId, dateTime: makeDate(day: 5, hour: 19))
let emptyStadiums: [UUID: Stadium] = [:]
let emptyStadiums: [String: Stadium] = [:]
let routes2 = GameDAGRouter.findRoutes(
games: [game],
@@ -271,9 +271,9 @@ struct EdgeCaseTests {
// Test with mismatched team IDs (homeTeamId and awayTeamId don't exist)
let game2 = Game(
id: UUID(),
homeTeamId: UUID(), // Non-existent team
awayTeamId: UUID(), // Non-existent team
id: "game_test_\(UUID().uuidString)",
homeTeamId: "team_nonexistent_\(UUID().uuidString)", // Non-existent team
awayTeamId: "team_nonexistent_\(UUID().uuidString)", // Non-existent team
stadiumId: stadiumId,
dateTime: makeDate(day: 5, hour: 19),
sport: .mlb,
@@ -298,8 +298,8 @@ struct EdgeCaseTests {
// Default: 8 hours/day * 60 mph * 2 days = 960 miles max
// With 1.3 road factor, haversine distance should be 960/1.3 738 miles
let stadiumId1 = UUID()
let stadiumId2 = UUID()
let stadiumId1 = "stadium_1_\(UUID().uuidString)"
let stadiumId2 = "stadium_2_\(UUID().uuidString)"
// NYC and Chicago are about 790 miles apart (haversine)
// With road factor 1.3, that's ~1027 road miles
@@ -344,8 +344,8 @@ struct EdgeCaseTests {
// NYC to LA is ~2,451 miles haversine, ~3,186 with road factor
// At 60 mph, that's ~53 hours - way over 16 hour limit
let stadiumId1 = UUID()
let stadiumId2 = UUID()
let stadiumId1 = "stadium_1_\(UUID().uuidString)"
let stadiumId2 = "stadium_2_\(UUID().uuidString)"
let nyc = makeStadium(id: stadiumId1, city: "New York", lat: 40.7128, lon: -73.9352)
let la = makeStadium(id: stadiumId2, city: "Los Angeles", lat: 34.0522, lon: -118.2437)
@@ -398,7 +398,7 @@ struct EdgeCaseTests {
// Calculate a point exactly 50 miles south (along a corridor)
// 1 degree of latitude 69 miles
// 50 miles 0.725 degrees
let stadiumId = UUID()
let stadiumId = "stadium_test_\(UUID().uuidString)"
let exactlyAtBoundary = makeStadium(
id: stadiumId,
city: "BoundaryCity",
@@ -434,7 +434,7 @@ struct EdgeCaseTests {
// Calculate a point 51 miles south (just outside the radius)
// 1 degree of latitude 69 miles
// 51 miles 0.739 degrees
let stadiumId = UUID()
let stadiumId = "stadium_test_\(UUID().uuidString)"
let justOutsideBoundary = makeStadium(
id: stadiumId,
city: "OutsideCity",
@@ -464,8 +464,8 @@ struct EdgeCaseTests {
@Test("11.9 - Game in different time zone normalizes correctly")
func test_gameInDifferentTimeZone_NormalizesToUTC() {
// Setup: Create games in different time zones
let stadiumId1 = UUID()
let stadiumId2 = UUID()
let stadiumId1 = "stadium_1_\(UUID().uuidString)"
let stadiumId2 = "stadium_2_\(UUID().uuidString)"
let nyc = makeStadium(id: stadiumId1, city: "New York", lat: 40.7128, lon: -73.9352)
let la = makeStadium(id: stadiumId2, city: "Los Angeles", lat: 34.0522, lon: -118.2437)
@@ -508,7 +508,7 @@ struct EdgeCaseTests {
@Test("11.10 - DST spring forward handled correctly")
func test_dstSpringForward_HandlesCorrectly() {
// Setup: Test around DST transition (Spring forward: March 8, 2026, 2 AM -> 3 AM)
let stadiumId = UUID()
let stadiumId = "stadium_test_\(UUID().uuidString)"
let chicago = makeStadium(id: stadiumId, city: "Chicago", lat: 41.8781, lon: -87.6298)
let stadiums = [stadiumId: chicago]
@@ -553,7 +553,7 @@ struct EdgeCaseTests {
@Test("11.11 - DST fall back handled correctly")
func test_dstFallBack_HandlesCorrectly() {
// Setup: Test around DST transition (Fall back: November 1, 2026, 2 AM -> 1 AM)
let stadiumId = UUID()
let stadiumId = "stadium_test_\(UUID().uuidString)"
let chicago = makeStadium(id: stadiumId, city: "Chicago", lat: 41.8781, lon: -87.6298)
let stadiums = [stadiumId: chicago]