Skip to content

Commit 68bde3c

Browse files
schwaaampclaude
andcommitted
Fix 3 defects in insight engine v3 intraday analyzers
1. Blacklist query error handling: log warning if insight_engine_blacklist table is missing instead of silently ignoring (pattern-spotter.ts) 2. Fix double-Z timestamp bug in sequential-change-analyzer: appending "Z" to localTimestamp that already ends with "Z" (from glucose display_time) produced "...ZZ" → NaN, silently breaking dawn phenomenon detection for CGM users 3. Standardize Z-suffix handling across all 4 intraday analyzers: use conditional append (ts.endsWith("Z") ? ts : ts + "Z") so hour extraction works correctly in both UTC production runtime and non-UTC dev environments Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent bc02fd4 commit 68bde3c

File tree

4 files changed

+11
-6
lines changed

4 files changed

+11
-6
lines changed

supabase/functions/_shared/excursion-cluster-analyzer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ function findExcursionStartHours(
8282
runLength++;
8383
} else {
8484
if (runLength >= minConsecutive) {
85-
const hour = new Date(sortedReadings[runStart].localTimestamp).getUTCHours();
85+
const hour = new Date(sortedReadings[runStart].localTimestamp.endsWith("Z") ? sortedReadings[runStart].localTimestamp : sortedReadings[runStart].localTimestamp + "Z").getUTCHours();
8686
startHours.push(hour);
8787
}
8888
runLength = 0;
@@ -91,7 +91,7 @@ function findExcursionStartHours(
9191

9292
// Handle trailing run
9393
if (runLength >= minConsecutive) {
94-
const hour = new Date(sortedReadings[runStart].localTimestamp).getUTCHours();
94+
const hour = new Date(sortedReadings[runStart].localTimestamp.endsWith("Z") ? sortedReadings[runStart].localTimestamp : sortedReadings[runStart].localTimestamp + "Z").getUTCHours();
9595
startHours.push(hour);
9696
}
9797

supabase/functions/_shared/sequential-change-analyzer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export function _computeDailyProfile(
7676

7777
for (const r of readings) {
7878
const date = r.localTimestamp.substring(0, 10);
79-
const hour = new Date(`${r.localTimestamp}Z`).getUTCHours();
79+
const hour = new Date(r.localTimestamp.endsWith("Z") ? r.localTimestamp : r.localTimestamp + "Z").getUTCHours();
8080
const bucket = Math.floor(hour / 3);
8181

8282
if (!dayBuckets.has(date)) {
@@ -147,7 +147,7 @@ export function analyzeSequentialChanges(
147147

148148
for (const r of config.readings) {
149149
const date = r.localTimestamp.substring(0, 10);
150-
const hour = new Date(`${r.localTimestamp}Z`).getUTCHours();
150+
const hour = new Date(r.localTimestamp.endsWith("Z") ? r.localTimestamp : r.localTimestamp + "Z").getUTCHours();
151151
const bucket = Math.floor(hour / 3);
152152

153153
if (!dayBuckets.has(date)) {

supabase/functions/_shared/temporal-distribution-analyzer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ export function analyzeTemporalDistribution(
101101
let maxTs = -Infinity;
102102

103103
for (const r of readings) {
104-
const d = new Date(r.localTimestamp);
104+
const tsForParse = r.localTimestamp.endsWith("Z") ? r.localTimestamp : r.localTimestamp + "Z";
105+
const d = new Date(tsForParse);
105106
const hour = d.getUTCHours();
106107
const bucketIdx = hourToBucket(hour);
107108
buckets[bucketIdx].push(r.value);

supabase/functions/ai-engine/engines/pattern-spotter.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,15 @@ export async function spotPatterns(
172172
const localTime = createLocalTimeExtractors(timezone);
173173

174174
// Load blacklist for tautological pair prevention
175-
const { data: blacklistRows } = await supabase
175+
const { data: blacklistRows, error: blacklistError } = await supabase
176176
.from('insight_engine_blacklist')
177177
.select('metric_a, metric_b')
178178
.eq('is_active', true);
179179

180+
if (blacklistError) {
181+
console.warn(`[PatternSpotter] ⚠ Failed to load blacklist: ${blacklistError.message} — continuing without blacklist`);
182+
}
183+
180184
const blacklist = new Set<string>(
181185
(blacklistRows ?? []).map((r: Record<string, unknown>) => `${r.metric_a}::${r.metric_b}`)
182186
);

0 commit comments

Comments
 (0)