Systematic audit of 1,191 tests found tests written to pass rather than
verify correctness. Key fixes:
Infrastructure:
- TestClock: fixed timezone from .current to America/New_York (deterministic)
- TestFixtures: added 1.3x road routing factor to match production
- ItineraryTestHelpers: real per-city coordinates instead of hardcoded (40,-80)
Planning tests:
- Added missing Scenario E factory dispatch tests
- Tightened 12 loose assertions (>= 1 → == 8.0, > 0 → range checks)
- Fixed 4 no-op tests that accepted both success and failure
- Fixed wrong repeat-city invariant (was checking same-day, not different-day)
- Fixed tautological assertion in missing-stadium edge case
Services/Domain/Export tests:
- Replaced 4 placeholder tests (#expect(true)) with real assertions
- Fixed tautological assertions in POISearchServiceTests
- Fixed Chicago coordinate in RegionMapSelectorTests (-89 → -87.6553)
- Added sort order verification to ItineraryRowFlatteningTests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds messy/realistic data factories to TestFixtures, new PlannerOutputSanityTests,
and updates all scenario planner tests with improved coverage and assertions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- RouteDescriptionGenerator: reuse session, cap tokens at 60, greedy
sampling, prewarm with prompt prefix, serial request queue with
rate-limit retry and circuit breaker
- Disable AI/template descriptions on trip option cards
- GameDAGRouter: fix off-by-one in canTransition driving constraint
(daysBetween+1) so multi-day cross-city routes aren't rejected
- CanonicalSyncService: wrap SyncStatusMonitor in #if DEBUG
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces fatalError with hardcoded production key so analytics
initializes correctly in TestFlight/App Store builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
The hardening pass incorrectly changed Game.gameDate to use UTC, which
broke timezone-dependent departure date calculations in ScenarioDPlanner.
Also widened the DAG router test's same-day game gap to account for the
new 3-hour game duration in canTransition.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Eliminate redundant 0-mile travel segments when start/end city matches
the first/last game stop city, and fail early when no games exist at
endpoint cities within the selected date range.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
LocationSearchSheet now shows only stadium cities (with sport badges) when
selecting start/end locations, preventing users from picking cities with no
stadiums. TripWizardViewModel filters available sports to the union of sports
at the selected cities, and clears invalid selections when locations change.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Change attraction category color from .yellow to orange variant for
readable text in both light and dark mode (QuickAddItemSheet, POIDetailSheet)
- Fix "optional" badge to use textPrimary-based colors for strong contrast
- Bump paywall dashed separator from 0.4 to 0.6 opacity
- Fix SuggestedTripCard bullet separator from textMuted(0.5) to textSecondary
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move .sheet(isPresented: $showPaywall) from subscription section to
top-level body so StoreManager state changes don't dismiss the sheet.
Reposition heart (16pt top/trailing) and map (16pt bottom/trailing,
above gradient) buttons on trip detail map.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the generic paywall header with a branded "SportsTime Pro / Your All-Access Pass"
hero section, 4 uniform feature cards (GeometryReader-sized squares), and a dashed ticket
perforation separator. Add "Show Paywall" debug button in Settings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds .contentShape(Rectangle()) or .contentShape(Capsule()) to 11 buttons,
NavigationLinks, and onTapGesture handlers across 8 files where only the
visible content (text/icons) was receiving taps instead of the full row.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gate Icon Generator section behind #if DEBUG and group it with other debug
sections at the bottom of Settings. Remove auto-focus on description field,
dismiss keyboard on return key and on scroll.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Final batch: F-082 (create poll with 2+ saved trips) and F-099 (progress
percentage updates after stadium visit). Also marks 9 more impossible tests
RED (F-016, F-039, F-048, F-050, F-107, F-108, F-111, F-129, F-130).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- F-015: Featured trips refresh button works without crash
- F-076: Trip detail loads correctly with single-stop trip
- F-094: Schedule diagnostics sheet opens from filter menu
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests that require network control, StoreKit sandbox, CloudKit
operations, photo permissions, visual verification, or missing
accessibility IDs are marked RED as not automatable via XCUITest.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds 3 new UI tests covering stadium visit manual entry, required field
validation, and games history navigation. Includes accessibility IDs on
StadiumVisitSheet/ProgressTabView and new page objects (StadiumVisitSheetScreen,
GamesHistoryScreen) in the test framework.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BGTaskScheduler.register(using: nil) invokes the handler on a background
queue, but the closure captured @MainActor-isolated self. Swift 6 runtime
enforces this with dispatch_assert_queue which crashed on Thread 4.
Fix: pass DispatchQueue.main as the handler queue so the callback runs
on the main queue, satisfying @MainActor isolation. Also fix expiration
handlers to capture a local Logger copy instead of accessing self.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Expand POI categories from 5 to 7 (restaurant, bar, coffee, hotel, parking, attraction, entertainment)
- Add category filter chips with per-category API calls and caching
- Add delete button with confirmation dialog to Edit Item sheet
- Fix itinerary items not persisting: use LocalItineraryItem (SwiftData) as primary store with CloudKit sync as secondary, register model in schema
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update games_canonical.json to use ISO 8601 UTC timestamps (game_datetime_utc)
- Fix BootstrapService timezone-aware parsing for venue-local fallback
- Fix thread-unsafe shared DateFormatter in RichGame local time display
- Bump SchemaVersion to 4 to force re-bootstrap with correct UTC data
- Restructure schedule view: group by date instead of sport, with sport
icons on each row and date section headers showing game counts
- Fix schedule row backgrounds using Theme.cardBackground instead of black
- Sort games by UTC time with local-time tiebreaker for same-instant games
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add mapItem field to POISearchService.POI for Apple Maps integration
- Merge description + location into single combined card in QuickAddItemSheet
- Auto-load nearby POIs when regionCoordinate is available, with detail sheet
- Create POIDetailSheet with map preview, metadata, and one-tap add-to-day
- Add poiAddedToDay/poiDetailViewed analytics events
- Add initial state to PlaceSearchSheet with search suggestions and flow layout
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>