window.ISR = window.ISR || {}; // ── LRU Track Cache ────────────────────────────────────────────── const TRACK_CACHE = new Map(); const TRACK_CACHE_MAX = 100; function cacheTrackData(frameIdx, data) { if (TRACK_CACHE.size >= TRACK_CACHE_MAX) { const oldest = TRACK_CACHE.keys().next().value; TRACK_CACHE.delete(oldest); } TRACK_CACHE.set(frameIdx, data); } function getCachedTracks(frameIdx) { if (!TRACK_CACHE.has(frameIdx)) return null; const data = TRACK_CACHE.get(frameIdx); TRACK_CACHE.delete(frameIdx); TRACK_CACHE.set(frameIdx, data); // promote to most-recent return data; } function clearTrackCache() { TRACK_CACHE.clear(); } // ── Assessment Cache ─────────────────────────────────────────────── // Carries GPT assessment data forward across frames per track_id const ASSESSMENT_CACHE = {}; // track_id → {satisfies, reason, mission_relevant, features, gpt_raw, assessment_status} function cacheAssessment(trackId, data) { if (!trackId) return; if (!ASSESSMENT_CACHE[trackId]) ASSESSMENT_CACHE[trackId] = {}; const c = ASSESSMENT_CACHE[trackId]; if (data.gpt_raw !== undefined) c.gpt_raw = data.gpt_raw; if (data.satisfies !== undefined) c.satisfies = data.satisfies; if (data.reason !== undefined) c.reason = data.reason; if (data.mission_relevant !== undefined) c.mission_relevant = data.mission_relevant; if (data.features !== undefined) c.features = data.features; if (data.assessment_status !== undefined) c.assessment_status = data.assessment_status; } function applyAssessmentCache(track) { const tid = track.track_id !== undefined ? track.track_id : track.id; // Cache new data if present (matches frontend tracker.js Phase 1) if (track.gpt_raw || track.assessment_status === 'ASSESSED') { cacheAssessment(tid, track); } // Apply cached data if track is missing gpt_raw (matches frontend tracker.js Phase 2) if (track.gpt_raw) return track; // Already has assessment data, skip const cached = ASSESSMENT_CACHE[tid]; if (!cached) return track; track.gpt_raw = cached.gpt_raw; if (cached.satisfies !== undefined) track.satisfies = cached.satisfies ?? track.satisfies; track.reason = cached.reason || track.reason; if (cached.mission_relevant !== undefined) track.mission_relevant = cached.mission_relevant ?? track.mission_relevant; track.assessment_status = cached.assessment_status || 'ASSESSED'; if (cached.features && Object.keys(cached.features).length > 0) track.features = cached.features; return track; } function clearAssessmentCache() { for (const k of Object.keys(ASSESSMENT_CACHE)) delete ASSESSMENT_CACHE[k]; } // ── Export to namespace ───────────────────────────────────────── Object.assign(window.ISR, { TRACK_CACHE, ASSESSMENT_CACHE, cacheTrackData, getCachedTracks, clearTrackCache, cacheAssessment, applyAssessmentCache, clearAssessmentCache, });