From d300a91b7d51a0b014e4465a3d47d8c2f914703d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Apr 2026 09:17:00 +0000 Subject: [PATCH 1/2] Initial plan From c730e617b4014c48183d91d265c247626e395cfa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Apr 2026 09:26:46 +0000 Subject: [PATCH 2/2] fix: trigger sleep score pipeline after recent health data sync when no prior summary existed When a user has HealthKit sleep data for recent dates (within 14 days) but the backend has no summary for those dates (e.g. because the app was not opened and health data was never uploaded), the previous code called triggerOnDemandPipelinesIfNeeded with a nil resolvedSummary, which returned immediately without triggering the score pipeline. The health data was then uploaded by syncRecentDateIfNeeded, but no score was ever computed. Fix: after syncRecentDateIfNeeded uploads health data and the summary is refreshed, check whether the score pipeline was not already triggered (onDemandTriggerResult.attemptedScore == false) and a summary is now available (resolvedSummary != nil). If both conditions hold, call triggerOnDemandPipelinesIfNeeded again so the backend can compute the score and subsequently surface recommendations. Agent-Logs-Url: https://github.com/SleepFocus/SleepFocus_Frontend/sessions/721ff11d-c1ae-4ce7-a851-c0e6963ec073 Co-authored-by: austinkimchi <40729751+austinkimchi@users.noreply.github.com> --- SleepFocus/Services/HomeSummaryStore.swift | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/SleepFocus/Services/HomeSummaryStore.swift b/SleepFocus/Services/HomeSummaryStore.swift index 739f766..d6d0100 100644 --- a/SleepFocus/Services/HomeSummaryStore.swift +++ b/SleepFocus/Services/HomeSummaryStore.swift @@ -160,6 +160,26 @@ final class HomeSummaryStore: ObservableObject { resolvedSummary = syncedSummary summary = syncedSummary } + + // Health data was just uploaded. If the score pipeline was not already + // triggered before the sync (e.g. because no summary existed yet), + // trigger it now so the backend can compute the score. + if !onDemandTriggerResult.attemptedScore, resolvedSummary != nil { + let postSyncTriggerResult = await triggerOnDemandPipelinesIfNeeded( + using: authManager, + for: selectedDate, + summary: resolvedSummary + ) + if postSyncTriggerResult.attemptedAny { + invalidateMonthCache(monthKey: selectedMonthKey) + guard isActiveLoad(loadToken) else { return } + if let refreshedSummary = await fetchSummary(using: authManager, for: selectedDate) { + cacheSummary(refreshedSummary, fallbackDate: selectedDate) + resolvedSummary = refreshedSummary + summary = refreshedSummary + } + } + } } if let currentSummary = resolvedSummary,