query('SELECT * FROM instruments')->fetchAll(); foreach($insts as $i){ $q=db()->prepare("SELECT MAX(r.ts) m FROM readings r JOIN streams s ON s.id=r.stream_id WHERE s.instrument_id=? AND r.is_placeholder=0"); $q->execute([$i['id']]); $last=$q->fetch()['m']; $live=db()->prepare("SELECT COUNT(*) c FROM streams WHERE instrument_id=? AND mode='live'"); $live->execute([$i['id']]); $isLive=$live->fetch()['c']>0; if(!$isLive){ $new='pending'; } else{ $age=$last?(time()-strtotime($last))/60:1e9; $new = $age < max(90,$i['cadence_min']*2) ? 'ok' : ($age < $i['cadence_min']*6 ? 'late' : 'silent'); } if($new!==$i['status']){ db()->prepare('UPDATE instruments SET status=? WHERE id=?')->execute([$new,$i['id']]); $class = in_array($new,['late','silent']) ? ($new==='silent'?'fault':'gap') : ($i['status']!=='pending'?'recovery':'info'); db()->prepare('INSERT INTO events(instrument_id,ts,class,detail,is_public) VALUES(?,NOW(),?,?,1)') ->execute([$i['id'],$class, $i['name'].': '.$i['status'].' → '.$new]); log_activity('cron','health_transition',$i['name'].' '.$i['status'].'→'.$new); if(in_array($new,['late','silent'])){ $throttled = $i['last_alert_at'] && (time()-strtotime($i['last_alert_at']) < ALERT_THROTTLE_HOURS*3600); if(!$throttled){ @mail(ALERT_EMAIL,'[Research Labs] '.$i['name'].' is '.$new, $i['name'].' ('.$i['product'].") transitioned to ".$new.".\nLast reading: ".($last?:'never')."\nHealth: ".BASE_URL."/index.php?p=health", 'From: '.ALERT_FROM); db()->prepare('UPDATE instruments SET last_alert_at=NOW() WHERE id=?')->execute([$i['id']]); log_activity('cron','alert_email',$i['name'].' '.$new); } } } } echo "health check complete\n";