fix: codebase audit fixes — safety, accessibility, and production hygiene

Address 16 issues from external audit:
- Move StoreKit transaction listener ownership to StoreManager singleton with proper deinit
- Remove noisy VoiceOver announcements, add missing accessibility on StatPill and BootstrapLoadingView
- Replace String @retroactive Identifiable with IdentifiableShareCode wrapper
- Add crash guard in AchievementEngine getContributingVisitIds + cache stadium lookups
- Pre-compute GamesHistoryViewModel filtered properties to avoid redundant SwiftUI recomputation
- Remove force-unwraps in ProgressMapView with safe guard-let fallback
- Add diff-based update gating in ItineraryTableViewWrapper to prevent unnecessary reloads
- Replace deprecated UIScreen.main with UIWindowScene lookup
- Add deinit task cancellation in ScheduleViewModel and SuggestedTripsGenerator
- Wrap ~234 unguarded print() calls across 27 files in #if DEBUG

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-02-22 00:07:53 -06:00
parent 826eadbc0f
commit 91c5eac22d
32 changed files with 434 additions and 67 deletions

View File

@@ -83,7 +83,9 @@ enum ItineraryReorderingLogic {
// nil is valid during initial display before travel is persisted.
let lookedUp = findTravelSortOrder(segment)
sortOrder = lookedUp ?? defaultTravelSortOrder
#if DEBUG
print("📋 [flattenDays] Travel \(segment.fromLocation.name)->\(segment.toLocation.name) on day \(day.dayNumber): lookedUp=\(String(describing: lookedUp)), using sortOrder=\(sortOrder)")
#endif
case .games, .dayHeader:
// These item types are not movable and handled separately.
@@ -319,6 +321,7 @@ enum ItineraryReorderingLogic {
}
// DEBUG: Log the row positions
#if DEBUG
print("🔢 [calculateSortOrder] row=\(row), day=\(day), gamesRow=\(String(describing: gamesRow))")
print("🔢 [calculateSortOrder] items around row:")
for i in max(0, row - 2)...min(items.count - 1, row + 2) {
@@ -326,6 +329,7 @@ enum ItineraryReorderingLogic {
let gMarker = (gamesRow == i) ? " [GAMES]" : ""
print("🔢 \(marker) [\(i)] \(items[i])\(gMarker)")
}
#endif
// Strict region classification:
// - row < gamesRow => before-games (negative sortOrder)
@@ -333,10 +337,14 @@ enum ItineraryReorderingLogic {
let isBeforeGames: Bool
if let gr = gamesRow {
isBeforeGames = row < gr
#if DEBUG
print("🔢 [calculateSortOrder] row(\(row)) < gamesRow(\(gr)) = \(isBeforeGames) → isBeforeGames=\(isBeforeGames)")
#endif
} else {
isBeforeGames = false // No games means everything is "after games"
#if DEBUG
print("🔢 [calculateSortOrder] No games on day \(day) → isBeforeGames=false")
#endif
}
/// Get sortOrder from a movable item (custom item or travel)
@@ -442,7 +450,9 @@ enum ItineraryReorderingLogic {
}
}
#if DEBUG
print("🔢 [calculateSortOrder] RESULT: \(result) (isBeforeGames=\(isBeforeGames))")
#endif
return result
}