Summary
In monitor mode, an entity (device / IP / application / protocol) is currently treated as active if and only if it appears in the latest snapshot, and absent otherwise. This binary rule is too naive: an entity missing from the most recent PCAP hasn't necessarily left the network — it may simply not have communicated during that capture window. A single quiet capture flips a still-present device to "absent".
We should let the user configure an inactivity threshold that governs when an entity is considered inactive, based on how recently it was last seen rather than "not in the latest snapshot".
Current behaviour
The active/absent split is computed client-side in the drift panels — DeviceDriftPanel, IpDriftPanel, ProtocolDriftPanel (and the app equivalent). The rule is identical in each: build a lastSeen map across all snapshots, then anything not present in the latest snapshot's key set is pushed into absentEntities (see frontend/src/components/monitor/DeviceDriftPanel/DeviceDriftPanel.tsx:52-88).
AbsentEntity (frontend/src/features/monitor/types/monitor.types.ts:104) already carries lastSeenFileName, lastSeenStartTime, lastSeenFileId.
LastSeenModal surfaces the last-seen file + capture start time to the user.
So the "last seen" snapshot + timestamp already exist — we just don't use them to make a threshold-based inactivity decision.
Proposed feature
Let the user configure an inactivity threshold under one of two modes. An entity is active if it's in the latest snapshot, inactive if it falls outside the configured threshold, and quiet (new) if it's absent from the latest snapshot but still within the threshold — i.e. it was just quiet in that window, not gone.
Mode A — days since last seen
An entity is inactive if it was last seen more than N days ago. The "how many days ago" is measured against a configurable reference point:
- Relative to the latest PCAP —
latestSnapshot.startTime − entity.lastSeenStartTime > N days. Anchoring to capture time (not wall-clock) is the right default for retrospective analysis of an already-collected set of PCAPs, where "today" is meaningless.
- Relative to today's date —
now − entity.lastSeenStartTime > N days. Appropriate for a live/ongoing monitored network where staleness against the real current date is what matters.
Mode B — last seen within the latest N PCAPs
An entity is inactive if it does not appear in any of the most recent N snapshots (ordered by capture start time). This is capture-count-based rather than time-based, which is the more natural threshold when captures are taken on an irregular cadence — "seen in at least one of the last 3 captures" is meaningful even when the gap between captures varies wildly, where a fixed day count would not be.
The three modes (days-relative-to-PCAP, days-relative-to-today, last-N-PCAPs) are mutually exclusive per network.
Configuration surface
- Threshold config lives per network (different networks have different capture cadences). Suggested shape on
NetworkEntity / NetworkDto:
inactivityMode (enum: DAYS | SNAPSHOTS)
inactivityThreshold (int — interpreted as days when DAYS, as a snapshot count when SNAPSHOTS)
inactivityReference (enum: LATEST_PCAP | TODAY) — only relevant when inactivityMode = DAYS
- Editable from
EditNetworkModal, defaulted at creation in CreateNetworkModal.
- Sensible defaults, e.g.
inactivityMode = DAYS, inactivityThreshold = 7, inactivityReference = LATEST_PCAP — preserving today's behaviour reasonably (with a small grace window instead of the current 0-day cliff).
- Flyway migration to add the columns.
Applying the threshold
Replace the binary "in latest snapshot ⇒ active" check in the drift panels with the three-way classification driven by the configured mode/threshold:
- Active — present in the latest snapshot.
- Quiet (new) — absent from the latest snapshot but within the threshold. Present it distinctly from truly inactive (e.g. a muted "quiet" badge rather than "absent"), so the user isn't misled into thinking it left.
- Inactive — outside the threshold (last seen > N days ago, or not in any of the last N snapshots).
The mode/threshold must be applied consistently across all four drift panels (device / IP / app / protocol) and reflected in the network diagram and any absent-entity counts.
Acceptance criteria
Notes / open questions
- The classification currently happens on the frontend. Given the config is per-network and needs to be consistent across panels, consider computing the active/quiet/inactive state server-side (or in a shared hook) rather than duplicating the day-/snapshot-math in each drift panel.
- UI should hide the
reference selector when SNAPSHOTS mode is chosen, since it doesn't apply.
Summary
In monitor mode, an entity (device / IP / application / protocol) is currently treated as active if and only if it appears in the latest snapshot, and absent otherwise. This binary rule is too naive: an entity missing from the most recent PCAP hasn't necessarily left the network — it may simply not have communicated during that capture window. A single quiet capture flips a still-present device to "absent".
We should let the user configure an inactivity threshold that governs when an entity is considered inactive, based on how recently it was last seen rather than "not in the latest snapshot".
Current behaviour
The active/absent split is computed client-side in the drift panels —
DeviceDriftPanel,IpDriftPanel,ProtocolDriftPanel(and the app equivalent). The rule is identical in each: build alastSeenmap across all snapshots, then anything not present in the latest snapshot's key set is pushed intoabsentEntities(seefrontend/src/components/monitor/DeviceDriftPanel/DeviceDriftPanel.tsx:52-88).AbsentEntity(frontend/src/features/monitor/types/monitor.types.ts:104) already carrieslastSeenFileName,lastSeenStartTime,lastSeenFileId.LastSeenModalsurfaces the last-seen file + capture start time to the user.So the "last seen" snapshot + timestamp already exist — we just don't use them to make a threshold-based inactivity decision.
Proposed feature
Let the user configure an inactivity threshold under one of two modes. An entity is active if it's in the latest snapshot, inactive if it falls outside the configured threshold, and quiet (new) if it's absent from the latest snapshot but still within the threshold — i.e. it was just quiet in that window, not gone.
Mode A — days since last seen
An entity is inactive if it was last seen more than N days ago. The "how many days ago" is measured against a configurable reference point:
latestSnapshot.startTime − entity.lastSeenStartTime > N days. Anchoring to capture time (not wall-clock) is the right default for retrospective analysis of an already-collected set of PCAPs, where "today" is meaningless.now − entity.lastSeenStartTime > N days. Appropriate for a live/ongoing monitored network where staleness against the real current date is what matters.Mode B — last seen within the latest N PCAPs
An entity is inactive if it does not appear in any of the most recent N snapshots (ordered by capture start time). This is capture-count-based rather than time-based, which is the more natural threshold when captures are taken on an irregular cadence — "seen in at least one of the last 3 captures" is meaningful even when the gap between captures varies wildly, where a fixed day count would not be.
The three modes (days-relative-to-PCAP, days-relative-to-today, last-N-PCAPs) are mutually exclusive per network.
Configuration surface
NetworkEntity/NetworkDto:inactivityMode(enum:DAYS|SNAPSHOTS)inactivityThreshold(int — interpreted as days whenDAYS, as a snapshot count whenSNAPSHOTS)inactivityReference(enum:LATEST_PCAP|TODAY) — only relevant wheninactivityMode = DAYSEditNetworkModal, defaulted at creation inCreateNetworkModal.inactivityMode = DAYS,inactivityThreshold = 7,inactivityReference = LATEST_PCAP— preserving today's behaviour reasonably (with a small grace window instead of the current 0-day cliff).Applying the threshold
Replace the binary "in latest snapshot ⇒ active" check in the drift panels with the three-way classification driven by the configured mode/threshold:
The mode/threshold must be applied consistently across all four drift panels (device / IP / app / protocol) and reflected in the network diagram and any absent-entity counts.
Acceptance criteria
inactivityMode(DAYS|SNAPSHOTS),inactivityThreshold(int ≥ 0), andinactivityReference(LATEST_PCAP|TODAY, used only inDAYSmode).EditNetworkModal, set on creation inCreateNetworkModal, persisted via Flyway migration +NetworkDto.DAYSmode with "relative to latest PCAP" measures days from the latest snapshot'sstartTime; with "relative to today" measures from the current date.SNAPSHOTSmode classifies an entity inactive when it appears in none of the most recent N snapshots.Notes / open questions
referenceselector whenSNAPSHOTSmode is chosen, since it doesn't apply.