The Detection Lifecycle
On the map, a camera glows to say it's currently detecting smoke or fire. That state has to turn on when detections start and — just as importantly — turn off when they stop, without a human closing anything. A detection isn't a moment; it's a window that opens on the first hit and closes automatically after the hits stop. This lesson is how that window is managed, because "is this camera detecting" is the piece of state operators trust most.
The one idea to hold on to
The "detecting" state is an active CondorEventEntity, kept alive by fresh detections and
closed automatically by a stale-event timer — with a change feed that reacts to the closure by
clearing the camera's flags. Three moving parts, one window:
Keeping the window open
Every detection (from the reconcile) does two things that keep the state alive:
- Refreshes the incident — the active
CondorEventEntitygetsLastUpdatedDate = nowand its TTL reset to 3 hours. As long as detections keep coming, the incident never goes stale. - Sets the camera flags — on the
CameraOperationaldoc:HasAiDetectionHit(any detection) plus the type-specificHasRecent60DetectionHit,HasRecentPanoDetectionHit, orHasRecentVideoDetectionHit, andLatestAiDetectionStartDate/LatestAiDetectionDate. These flags are exactly what the frontend reads to render the "detecting" indicator.
So while a fire is being detected, each new hit slides the window forward — the camera stays lit.
Closing the window, automatically
When detections stop, two functions cooperate to close the window — and the split between them is a clean example of separating a decision from its effect:
CleanupStaleDetectionFlags(timer, every 2 minutes) makes the decision. It finds activeCondorEventEntitys whoseLastUpdatedDateis older than 10 minutes and sets their status toExpired. Ten minutes of silence means the window is over.CondorEventChangeFeed(a Cosmos change-feed trigger on thecondorEventcontainer) applies the effect. It reacts only to events that have moved away fromActive, and callsResetCameraDetectionFlags— clearingHasAiDetectionHitand the type flags and nullingLatestAiDetectionStartDate. The camera stops glowing.
The timer decides when; the change feed reacts to the resulting status change to update the camera. Either the timer expires an event, or something else resolves it — either way the change feed is the single place the flags get cleared, so they can't be forgotten.
There are two different timers on the incident and they do different jobs. The 10-minute staleness check is the one that drives the UX: it's what turns "detecting" off promptly after detections stop. The 3-hour TTL on the Cosmos doc is a backstop — Cosmos deletes the event document outright after that, so even if the timer or change feed failed, an incident can't live forever. Don't confuse them: raise the 10-minute value to keep cameras "detecting" longer; the TTL is just garbage collection.
Wrapping up
A camera's "detecting" state is an active Cosmos CondorEventEntity that fresh detections keep
alive (refreshing its LastUpdatedDate and 3-hour TTL, and setting the camera flags). A
2-minute timer expires events after 10 minutes of silence, and the condorEvent change feed
reacts to that status change by clearing the camera's flags — so the window closes on its own.
The 10-minute check drives the UX; the TTL is a backstop.
Detections light up the map and the console for operators. The other half of the app turns a confirmed threat into a message people act on. Next: From Alert to Reaction.