Moderate risk alert at midnight, awake at the desk
A side-project safety app generated a moderate-severity risk alert for me at 00:28 local time. I was at my desk, awake, trading messages with two different people on Signal. The alert was false. Walking through why turned into a useful exercise in "what signals should trump what."
What was happening
The risk evaluator looks at recent activity inside the cron window. If activity is low and the time is outside the user's learned wake window, it flips the moderate risk factor on. At 00:28 I was past my median bed time, hadn't tapped the app in a while (most of my recent activity was elsewhere on the phone), and the cron correctly identified that as quiet from its perspective.
But "no activity inside the app" and "no activity at all" are not the same thing.
What I found
Three things compounded:
- The risk evaluator was scoring against the learned per-DOW wake window. That window placed my "should be active" bound somewhere around 00:00 — I'm a night owl, but only sometimes, and the median doesn't capture the variance.
- The app's activity table only sees events the app itself generates: app-foreground taps, location updates from the tracker, etc. Messaging traffic outside the app is invisible.
- There's no "you're home and demonstrably alive" suppressor for moderate alerts. The hard inactivity alert path has one (it tries an AI evaluator with full context); the moderate risk path doesn't.
The fix
The fix I wrote down was: "consider suppressing moderate alerts when location=home AND there's recent passive evidence of activity in the same timeframe." The trick is what counts as passive evidence if the user isn't using the app. Some candidates I considered:
- Recent location pings with non-zero speed → "phone is being carried, user is moving"
- Recent screen-on events from the OS (iOS and Android both expose enough to infer this)
- A coarse "did the phone move at all" signal from the motion sensor over the last N minutes
For now the change I shipped was simpler: any GPS update within the last 15 minutes counts as a "passive heartbeat" for moderate-severity suppression at home. Doesn't help if the phone is sitting still on the desk, but covers the much more common case where the user is moving around the house. The risk evaluator now reads:
if ($severity <= RISK_MODERATE
&& $atHome
&& $minutesSinceLastFix < 15) {
return null; // suppress
}
Hard inactivity and SOS paths are unaffected — those should still page through this kind of guard.
What I'd do differently
The deeper fix is to feed the AI evaluator into moderate
alerts the same way it feeds hard alerts. The prompt would
get in_sleep_window, at_home, minutes_since_last_fix,
recent_signal_traffic_detected, etc., and decide whether to
suppress. That's more work and more cost, and the simple
heuristic above closes the specific case that fired.
The bigger lesson: don't infer "not alive" from "no events in the app." A safety system has to consider whatever signals the phone can provide as evidence of the user being okay, not just app events. If the user is moving their phone around, the system should know that without needing them to open the app.