Skip to content

Commit faa8723

Browse files
committed
fix: map awareness score to yes/somewhat/no for Supabase upload
Supabase blackout_events table has a CHECK constraint that only allows "yes", "somewhat", "no", or null in the awareness column. Numeric scores were rejected with HTTP 400, causing silent upload failures. Score mapping: 0–33 → "no", 34–66 → "somewhat", 67–100 → "yes". Full 0–100 granularity is preserved locally in ProgressTracker.
1 parent 1fd25ae commit faa8723

6 files changed

Lines changed: 39 additions & 9 deletions

File tree

‎Sources/Awareness/Blackout/BlackoutWindowController.swift‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,12 @@ class BlackoutWindowController {
323323
state.microTask = task
324324
state.onAwarenessAnswered = { [weak self] in
325325
guard let self = self, self.isActive, self.isInPostBlackoutPhase else { return }
326-
// Capture awareness score for sync upload
326+
// Capture awareness for sync upload (mapped to Supabase format:
327+
// CHECK constraint only allows "yes"/"somewhat"/"no")
327328
if let score = state.awarenessScore {
328-
self.syncEventAwareness = "\(score)"
329+
if score >= 67 { self.syncEventAwareness = "yes" }
330+
else if score >= 34 { self.syncEventAwareness = "somewhat" }
331+
else { self.syncEventAwareness = "no" }
329332
}
330333
state.phase = .practiceCard
331334
}

‎ios/Awareness/Awareness/Blackout/BlackoutView.swift‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,9 @@ struct BlackoutView: View {
253253
/// Record awareness score and dismiss
254254
private func handleAwarenessScore(_ score: Int) {
255255
ProgressTracker.shared.recordAwarenessScore(score)
256-
// Upload final sync event with awareness score (upserts the start event)
257-
uploadSyncEvent(completed: true, awareness: "\(score)")
256+
// Upload final sync event with awareness mapped to Supabase format
257+
// (Supabase CHECK constraint only allows "yes"/"somewhat"/"no"/null)
258+
uploadSyncEvent(completed: true, awareness: Self.awarenessForSync(score))
258259
withAnimation(.easeOut(duration: 0.3)) {
259260
opacity = 0
260261
}
@@ -264,6 +265,15 @@ struct BlackoutView: View {
264265
}
265266
}
266267

268+
/// Map a 0–100 awareness score to Supabase-compatible string.
269+
/// Supabase CHECK constraint only allows "yes"/"somewhat"/"no".
270+
/// 0–33 → "no", 34–66 → "somewhat", 67–100 → "yes"
271+
private static func awarenessForSync(_ score: Int) -> String {
272+
if score >= 67 { return "yes" }
273+
if score >= 34 { return "somewhat" }
274+
return "no"
275+
}
276+
267277
// MARK: - Sync Upload
268278

269279
/// Upload the current blackout state to Supabase (upserts on sync_key + started_at + source)

‎ios/Awareness/Awareness/Sync/SupabaseClient.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ final class SupabaseClient {
2020
let startedAt: String // ISO 8601 timestamp
2121
let duration: Double // seconds
2222
let completed: Bool
23-
let awareness: String? // numeric "0"–"100" or legacy "yes"/"somewhat"/"no" / null
23+
let awareness: String? // "yes" / "somewhat" / "no" / null
2424
let source: String // "macos" / "windows" / "ios" / "watchos"
2525
let createdAt: String // ISO 8601 timestamp
2626

‎ios/Awareness/AwarenessWatch/BlackoutView.swift‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ struct BlackoutView: View {
290290
startedAt: start,
291291
duration: WatchConnectivityManager.lastBlackoutDuration,
292292
completed: WatchConnectivityManager.lastBlackoutCompleted,
293-
awareness: "\(score)"
293+
awareness: Self.awarenessForSync(score)
294294
)
295295
}
296296
WKInterfaceDevice.current().play(.click)
@@ -305,6 +305,14 @@ struct BlackoutView: View {
305305
}
306306
}
307307

308+
/// Map a 0–100 awareness score to Supabase-compatible string.
309+
/// Supabase CHECK constraint only allows "yes"/"somewhat"/"no".
310+
private static func awarenessForSync(_ score: Int) -> String {
311+
if score >= 67 { return "yes" }
312+
if score >= 34 { return "somewhat" }
313+
return "no"
314+
}
315+
308316
// MARK: - End Signal Notification
309317

310318
/// Schedule a local notification as a backup end signal.

‎ios/Awareness/AwarenessWatch/ContentView.swift‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ struct ContentView: View {
308308
startedAt: start,
309309
duration: WatchConnectivityManager.lastBlackoutDuration,
310310
completed: WatchConnectivityManager.lastBlackoutCompleted,
311-
awareness: "\(score)"
311+
awareness: awarenessForSync(score)
312312
)
313313
}
314314
WKInterfaceDevice.current().play(.click)
@@ -320,6 +320,14 @@ struct ContentView: View {
320320
}
321321
}
322322

323+
/// Map a 0–100 awareness score to Supabase-compatible string.
324+
/// Supabase CHECK constraint only allows "yes"/"somewhat"/"no".
325+
private func awarenessForSync(_ score: Int) -> String {
326+
if score >= 67 { return "yes" }
327+
if score >= 34 { return "somewhat" }
328+
return "no"
329+
}
330+
323331
// MARK: - Computed
324332

325333
private var statusColor: Color {

‎windows/Awareness/Blackout/BlackoutWindowController.cs‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,9 @@ private void BeginPostBlackoutPhase()
270270
_isInAwarenessCheckPhase = false;
271271
ProgressTracker.Shared.RecordAwarenessScore(score);
272272

273-
// Capture awareness score for sync upload
274-
_syncEventAwareness = score.ToString();
273+
// Capture awareness for sync upload (mapped to Supabase format:
274+
// CHECK constraint only allows "yes"/"somewhat"/"no")
275+
_syncEventAwareness = score >= 67 ? "yes" : score >= 34 ? "somewhat" : "no";
275276

276277
if (card != null)
277278
{

0 commit comments

Comments
 (0)