Skip to content

Add per-zone max_age overrides for tracker lifecycle#76

Open
2024itb047samata wants to merge 13 commits into
Devnil434:mainfrom
2024itb047samata:feat/per-zone-max-age
Open

Add per-zone max_age overrides for tracker lifecycle#76
2024itb047samata wants to merge 13 commits into
Devnil434:mainfrom
2024itb047samata:feat/per-zone-max-age

Conversation

@2024itb047samata
Copy link
Copy Markdown
Contributor

@2024itb047samata 2024itb047samata commented May 16, 2026

Summary
Implemented configurable per-zone max_age overrides for tracker persistence behavior.

Changes

  • Added optional max_age_override field to zone definitions
  • Applied dynamic zone-specific expiration logic during LOST handling
  • Preserved fallback to global tracker max_age
  • Maintained backward compatibility for zones without overrides

Behavior

Summary by CodeRabbit

  • Bug Fixes
    • Zone assignment now uses a fixed priority so overlapping zones are resolved predictably (e.g., keypad area takes precedence).
    • Tracking lifecycle events, dwell-time reporting, and lost-object recovery behavior remain consistent despite internal handling changes.
    • Internal memory handling and import formatting were adjusted with no changes to public APIs or observable behavior.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Tracker.update() now centers each bbox to get zones, sorts zones by a fixed ZONE_PRIORITY before emitting/saving, and refactors the single-frame lost-track lookup into a multiline next(...) call; memory imports were reformatted and a new get_active_track_ids method was inserted in MemoryStore.

Changes

Track lifecycle and ReID state management

Layer / File(s) Summary
Active track zone assignment and BORN emission
services/tracking/tracker.py
Compute bbox center (cx,cy), call get_zones_for_point(cx, cy), sort returned zones by ZONE_PRIORITY (e.g., keypad_area before restricted_door), then emit TrackState.BORN, update dwell counters, and persist active track state.
Lost/dead handling and embedding capture (lookup refactor)
services/tracking/tracker.py
On first-frame disappearance, locate the corresponding DeepSort track using a multiline next(...) lookup, capture its embedding into _lost_embeddings (or fallback), emit TrackState.LOST, and when age >= max_age emit TrackState.DEAD and clean up state.
Memory import change and overlapping get_active_track_ids insertion
services/memory/memory.py
Reformats libs.schemas.memory import removing ActionHint from the import list, and inserts a new MemoryStore.get_active_track_ids(camera_id: str) -> set[int] implementation that collects Redis smembers into a local result set (creating overlapping logic with an existing method later in the file).

Sequence Diagram(s)

sequenceDiagram
  participant DeepSort
  participant Tracker
  participant ZoneService
  participant EmissionService
  participant MemoryStore

  DeepSort->>Tracker: confirmed track (bbox, id, features)
  Tracker->>ZoneService: get_zones_for_point(cx, cy)
  ZoneService-->>Tracker: zone list
  Tracker->>Tracker: sort zones by ZONE_PRIORITY
  Tracker->>EmissionService: emit TrackState.BORN (zones, dwell)
  Tracker->>MemoryStore: persist/refresh active track entry

  Note over Tracker,DeepSort: on disappearance (frames_since == 1)
  Tracker->>DeepSort: next(...) lookup for matching track
  DeepSort-->>Tracker: track/features or None
  Tracker->>MemoryStore: store embedding in _lost_embeddings
  Tracker->>EmissionService: emit TrackState.LOST
  Tracker->>Tracker: when age >= max_age -> emit TrackState.DEAD and cleanup
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hop to centers where the bounding boxes lie,
I ask the zones which secrets they hide,
I rank the keypad, then door, in quiet order,
I hold a face when footsteps cross the border,
and when time runs out, I gently let it fly.

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The memory.py changes (new get_active_track_ids method and import reformatting) appear tangential to the core max_age override objective and introduce potential issues like method duplication. Remove or clarify the purpose of the get_active_track_ids implementation and ActionHint import changes in memory.py, as they fall outside the stated max_age override scope.
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive The changes update zone assignment logic (tracker.py) and introduce zone-aware infrastructure (memory.py), but the summary lacks evidence that max_age_override values are actually read from config or applied during LOST handling as required by issue #65. Clarify whether zone-specific max_age overrides are read from config/zones.yaml and applied dynamically during LOST track handling as stated in issue #65 requirements.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly summarizes the main change: adding per-zone max_age overrides for tracker lifecycle, which matches the stated objective in issue #65.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
services/tracking/tracker.py (2)

295-309: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Dedent cleanup and return TrackedFrame(...) out of the LOST branch.

With the current indentation, update() returns after the first disappeared track and falls off the end entirely on frames where nothing is lost.

Suggested fix
-                expired_ids = [
-                    tid for tid, data in self._lost_embeddings.items()
-                    if self._frame_id - data["last_seen"] > self.max_age
-                ]
-
-                for tid in expired_ids:
-                    del self._lost_embeddings[tid]
-                return TrackedFrame(
+        expired_ids = [
+            lost_tid for lost_tid, data in self._lost_embeddings.items()
+            if self._frame_id - data["last_seen"] > self.max_age
+        ]
+
+        for lost_tid in expired_ids:
+            del self._lost_embeddings[lost_tid]
+
+        return TrackedFrame(
             frame_id     = self._frame_id,
             camera_id    = self.camera_id,
             tracks       = tracked_objects,
             timestamp_ms = time.time() * 1000,
             fps          = self.fps,
         )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/tracking/tracker.py` around lines 295 - 309, The return of
TrackedFrame is accidentally inside the "LOST" branch causing update() to exit
early; move the return out of that block so it always executes. Specifically, in
update() adjust the indentation so that the cleanup of self._lost_embeddings
(building expired_ids and deleting them) completes, then the function returns
the TrackedFrame constructed with frame_id=self._frame_id,
camera_id=self.camera_id, tracks=tracked_objects, timestamp_ms=time.time()*1000,
fps=self.fps outside the LOST branch, ensuring expired_ids/max_age logic runs
but does not cause an early return.

341-354: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Move _cosine_similarity inside the Tracker class.

It is currently defined at module scope (line 341), so calling self._cosine_similarity(...) at line 140 will raise AttributeError at runtime.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/tracking/tracker.py` around lines 341 - 354, The helper function
_cosine_similarity is currently defined at module scope but is referenced as an
instance method (self._cosine_similarity) from the Tracker class; move its
definition inside the Tracker class body (as a private instance method) so it
becomes Tracker._cosine_similarity and can be called via
self._cosine_similarity(a, b). Ensure the signature and logic remain the same
(parameters a: np.ndarray, b: np.ndarray, return float) and update any
imports/indentation accordingly so it is indented as a method of class Tracker.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@services/tracking/tracker.py`:
- Around line 261-281: The code incorrectly uses only prev_obj.zones_present[0]
to pick a max_age_override; instead, look up all zones referenced in
prev_obj.zones_present against DEFAULT_ZONES, collect their max_age_override
values, and compute effective_max_age by an explicit precedence rule (prefer a
zone.priority attribute if present—select the zone with highest priority—or if
no priority field exists, choose the most restrictive override e.g., the
smallest non-None max_age_override); replace the single-zone lookup block around
prev_obj.zones_present, DEFAULT_ZONES, zone.max_age_override and
effective_max_age with this aggregation+precedence logic so overrides are
consistently applied regardless of list order.
- Around line 252-290: After emitting TrackState.DEAD you must remove the track
id from the track registry so it doesn't repeatedly re-enter the LOST/DEAD
branch; locate the block where frames_since > effective_max_age triggers
self._emit_lifecycle(TrackState.DEAD, tid, ...) and after that call remove the
track from self._active_tracks (and any related per-track state if applicable)
keyed by tid so the dead track is no longer considered on subsequent frames
(ensure you reference tid and _active_tracks and keep the _emit_lifecycle call
intact).

---

Outside diff comments:
In `@services/tracking/tracker.py`:
- Around line 295-309: The return of TrackedFrame is accidentally inside the
"LOST" branch causing update() to exit early; move the return out of that block
so it always executes. Specifically, in update() adjust the indentation so that
the cleanup of self._lost_embeddings (building expired_ids and deleting them)
completes, then the function returns the TrackedFrame constructed with
frame_id=self._frame_id, camera_id=self.camera_id, tracks=tracked_objects,
timestamp_ms=time.time()*1000, fps=self.fps outside the LOST branch, ensuring
expired_ids/max_age logic runs but does not cause an early return.
- Around line 341-354: The helper function _cosine_similarity is currently
defined at module scope but is referenced as an instance method
(self._cosine_similarity) from the Tracker class; move its definition inside the
Tracker class body (as a private instance method) so it becomes
Tracker._cosine_similarity and can be called via self._cosine_similarity(a, b).
Ensure the signature and logic remain the same (parameters a: np.ndarray, b:
np.ndarray, return float) and update any imports/indentation accordingly so it
is indented as a method of class Tracker.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: db568d0d-a304-4bab-9ac3-233af32f10a4

📥 Commits

Reviewing files that changed from the base of the PR and between e8cd4ce and a653513.

📒 Files selected for processing (2)
  • services/detection/zones.py
  • services/tracking/tracker.py

Comment thread services/tracking/tracker.py
Comment thread services/tracking/tracker.py Outdated
Comment on lines +261 to +281
if prev_obj.zones_present:

zone_name = prev_obj.zones_present[0]

from services.detection.zones import DEFAULT_ZONES

zone = next(
(
z for z in DEFAULT_ZONES
if z.name == zone_name
),
None,
)

if (
zone
and zone.max_age_override is not None
):
effective_max_age = (
zone.max_age_override
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't derive the override from zones_present[0].

keypad_area is nested inside restricted_door, and get_zones_for_point() preserves DEFAULT_ZONES order. That means a track inside the keypad resolves to restricted_door first, so the 15-frame override never applies. Compute effective_max_age from all matching zones with an explicit precedence rule instead of relying on list order.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/tracking/tracker.py` around lines 261 - 281, The code incorrectly
uses only prev_obj.zones_present[0] to pick a max_age_override; instead, look up
all zones referenced in prev_obj.zones_present against DEFAULT_ZONES, collect
their max_age_override values, and compute effective_max_age by an explicit
precedence rule (prefer a zone.priority attribute if present—select the zone
with highest priority—or if no priority field exists, choose the most
restrictive override e.g., the smallest non-None max_age_override); replace the
single-zone lookup block around prev_obj.zones_present, DEFAULT_ZONES,
zone.max_age_override and effective_max_age with this aggregation+precedence
logic so overrides are consistently applied regardless of list order.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
services/tracking/tracker.py (1)

255-264: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Per-zone max_age_override logic is missing and zones schema needs extension.

The code at line 255 only checks the global self._tracker.max_age without any zone-specific override logic. To implement the PR objective of "dynamic, zone-specific expiration logic," you need to:

  1. Add max_age_override field to the zone schema in config/zones.yaml
  2. Update zone_loader.py to load and validate this optional field
  3. Modify tracker.py line 255 to look up the zone-specific override from prev_obj.zones_present[0] and fall back to the global max_age if absent

Currently, zones are loaded with only: name, polygon, alert_on_entry, color_hex. The zone-specific timeout feature is not implemented despite the merged feature branch.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/tracking/tracker.py` around lines 255 - 264, The tracker currently
uses only the global timeout self._tracker.max_age when expiring tracks;
implement per-zone overrides by (1) adding an optional max_age_override field to
the zones schema in config/zones.yaml, (2) updating zone_loader.py to parse and
validate max_age_override into each Zone object (keeping it optional and
defaulting to None), and (3) changing the expiration logic in tracker.py (around
the block using frames_since and self._tracker.max_age and referencing
prev_obj.zones_present) to determine timeout = zone.max_age_override if present
for prev_obj.zones_present[0] else self._tracker.max_age before comparing
frames_since, then use that timeout for emitting DEAD lifecycle and deleting
from _active_tracks/_active_embeddings; keep existing calls to _emit_lifecycle
and logging intact.
🧹 Nitpick comments (1)
services/tracking/tracker.py (1)

189-193: ⚡ Quick win

Remove duplicate dwell computation.

Lines 186–187 already compute dwell_frames and dwell_secs identically; the repeated assignment at 189–193 is dead code.

♻️ Proposed fix
             prev = self._active_tracks.get(tid)
             dwell_frames = (prev.dwell_time_frames + 1) if prev else 1
             dwell_secs = dwell_frames / self.fps

-            dwell_frames = (
-                prev.dwell_time_frames + 1
-            ) if prev else 1
-
-            dwell_secs = dwell_frames / self.fps
-
             prev_traj = prev.trajectory if prev else []
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/tracking/tracker.py` around lines 189 - 193, The block duplicates
the dwell computation: remove the redundant reassignment of dwell_frames and
dwell_secs (the second occurrence that uses prev and self.fps) so only the first
computation remains; locate the duplicate in tracker.py where dwell_frames and
dwell_secs are assigned (references: variable names dwell_frames, dwell_secs,
prev and attribute self.fps, within the tracking update logic/function) and
delete the later repeated lines to avoid dead code.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@services/tracking/tracker.py`:
- Around line 212-215: In the loop where you create and register new
TrackedObject instances (you assign self._active_tracks[tid] = obj and
current_ids.add(tid)), also append each obj to the tracked_objects list so that
the resulting TrackedFrame.tracks is populated; specifically, add
tracked_objects.append(obj) immediately after setting self._active_tracks[tid] =
obj (using the existing variables tid, obj, current_ids, tracked_objects) so
downstream consumers receive the created tracks.

---

Outside diff comments:
In `@services/tracking/tracker.py`:
- Around line 255-264: The tracker currently uses only the global timeout
self._tracker.max_age when expiring tracks; implement per-zone overrides by (1)
adding an optional max_age_override field to the zones schema in
config/zones.yaml, (2) updating zone_loader.py to parse and validate
max_age_override into each Zone object (keeping it optional and defaulting to
None), and (3) changing the expiration logic in tracker.py (around the block
using frames_since and self._tracker.max_age and referencing
prev_obj.zones_present) to determine timeout = zone.max_age_override if present
for prev_obj.zones_present[0] else self._tracker.max_age before comparing
frames_since, then use that timeout for emitting DEAD lifecycle and deleting
from _active_tracks/_active_embeddings; keep existing calls to _emit_lifecycle
and logging intact.

---

Nitpick comments:
In `@services/tracking/tracker.py`:
- Around line 189-193: The block duplicates the dwell computation: remove the
redundant reassignment of dwell_frames and dwell_secs (the second occurrence
that uses prev and self.fps) so only the first computation remains; locate the
duplicate in tracker.py where dwell_frames and dwell_secs are assigned
(references: variable names dwell_frames, dwell_secs, prev and attribute
self.fps, within the tracking update logic/function) and delete the later
repeated lines to avoid dead code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7c05c7ae-f7e7-4704-8a49-3cad143c93ff

📥 Commits

Reviewing files that changed from the base of the PR and between a653513 and 0de2d0d.

📒 Files selected for processing (1)
  • services/tracking/tracker.py

Comment thread services/tracking/tracker.py
@Devnil434
Copy link
Copy Markdown
Owner

fix as per suggestions

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
services/tracking/tracker.py (1)

260-267: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Per-zone max_age_override is not applied in LOST→DEAD transition.

Expiry still uses only self._tracker.max_age (Line 266), so zone-specific retention from issue #65 is bypassed. Compute effective_max_age from prev_obj.zones_present by reading each zone’s max_age_override, then fall back to global max_age when none exists.

Suggested minimal patch
@@
-                if frames_since >= self._tracker.max_age:
+                zone_overrides = []
+                for zone_name in prev_obj.zones_present:
+                    zone = next((z for z in DEFAULT_ZONES if z.name == zone_name), None)
+                    if zone is not None and zone.max_age_override is not None:
+                        zone_overrides.append(zone.max_age_override)
+
+                effective_max_age = (
+                    min(zone_overrides) if zone_overrides else self._tracker.max_age
+                )
+
+                if frames_since >= effective_max_age:
                     self._emit_lifecycle(
                         TrackState.DEAD,
                         tid,
                         prev_obj.zones_present,
                         prev_obj.dwell_time_seconds,
                     )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/tracking/tracker.py` around lines 260 - 267, The LOST→DEAD expiry
uses self._tracker.max_age directly; change it to compute an effective_max_age
from prev_obj.zones_present by reading each zone's max_age_override (e.g.,
collect overrides for zones in prev_obj.zones_present, use the maximum override
if any exist, otherwise fall back to self._tracker.max_age) and then replace the
frames_since >= self._tracker.max_age check with frames_since >=
effective_max_age before calling _emit_lifecycle/TrackState.DEAD; update logic
around frames_since, _emit_lifecycle, prev_obj.zones_present, and
max_age_override accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@services/tracking/tracker.py`:
- Around line 260-267: The LOST→DEAD expiry uses self._tracker.max_age directly;
change it to compute an effective_max_age from prev_obj.zones_present by reading
each zone's max_age_override (e.g., collect overrides for zones in
prev_obj.zones_present, use the maximum override if any exist, otherwise fall
back to self._tracker.max_age) and then replace the frames_since >=
self._tracker.max_age check with frames_since >= effective_max_age before
calling _emit_lifecycle/TrackState.DEAD; update logic around frames_since,
_emit_lifecycle, prev_obj.zones_present, and max_age_override accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b94ae30d-514b-48b2-8746-6ac4094aab47

📥 Commits

Reviewing files that changed from the base of the PR and between 0de2d0d and d99707d.

📒 Files selected for processing (1)
  • services/tracking/tracker.py

@2024itb047samata
Copy link
Copy Markdown
Contributor Author

2024itb047samata commented May 19, 2026

@Devnil434 I did all the possible changes but could'nt figure out why it is failing in this test? Please mark it gssoc approved and difficulty in this PR and the other 3 PRs that is already merged #48 #53 #59 . Thank You!

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@services/memory/memory.py`:
- Around line 39-42: The import list in services/memory/memory.py dropped
ActionHint but store_event() still references ActionHint.ZONE_ENTRY; restore
ActionHint in the from libs.schemas.memory import (...) line so ActionHint is
available to the module and lint/runtime errors are resolved (search for the
import and the store_event function to update the import tuple to include
ActionHint).
- Around line 350-353: A newly inserted get_active_track_ids definition was
placed in the middle of get_sequence, truncating get_sequence after raw_list,
duplicating get_active_track_ids later, and calling self._active_key(camera_id)
even though _active_key() takes no arguments; to fix, remove the misplaced
duplicate method so get_sequence retains its full body (including use of
raw_list), keep a single get_active_track_ids implementation positioned below
get_zone_entry_count, and update any _active_key(...) calls to call
_active_key() with no arguments; reference get_sequence, get_active_track_ids,
get_zone_entry_count, raw_list, and _active_key when making the changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a24a8150-a277-4a6c-9e51-2af226e8ca11

📥 Commits

Reviewing files that changed from the base of the PR and between 701bd06 and 224b6a7.

📒 Files selected for processing (2)
  • services/memory/memory.py
  • services/tracking/tracker.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • services/tracking/tracker.py

Comment thread services/memory/memory.py
Comment on lines +39 to +42
from libs.schemas.memory import (
TrackEvent,
TrackSequence,
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Restore ActionHint in this import.

store_event() still compares event.action_hint to ActionHint.ZONE_ENTRY at Line 329, so dropping the import makes the module fail lint and raises on that path at runtime.

🐛 Minimal fix
 from libs.schemas.memory import (
+    ActionHint,
     TrackEvent,
     TrackSequence,
 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
from libs.schemas.memory import (
TrackEvent,
TrackSequence,
)
from libs.schemas.memory import (
ActionHint,
TrackEvent,
TrackSequence,
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/memory/memory.py` around lines 39 - 42, The import list in
services/memory/memory.py dropped ActionHint but store_event() still references
ActionHint.ZONE_ENTRY; restore ActionHint in the from libs.schemas.memory import
(...) line so ActionHint is available to the module and lint/runtime errors are
resolved (search for the import and the store_event function to update the
import tuple to include ActionHint).

Comment thread services/memory/memory.py
Comment on lines +350 to +353
def get_active_track_ids(self, camera_id: str) -> set[int]:
members = self._r.smembers(self._active_key(camera_id))
result: set[int] = set()
for m in members:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

This insertion breaks get_sequence() and duplicates get_active_track_ids().

Placing a new method here ends get_sequence() right after raw_list, pulls the rest of its body into the wrong scope, and then gets shadowed again by the existing get_active_track_ids() at Lines 379-382. The new call to self._active_key(camera_id) is also invalid because _active_key() takes no argument.

🐛 Suggested correction
-    def get_active_track_ids(self, camera_id: str) -> set[int]:
-        members = self._r.smembers(self._active_key(camera_id))
-        result: set[int] = set()
-        for m in members:
+        events: list[TrackEvent] = []
+        for raw in raw_list:

Keep the single get_active_track_ids() implementation below get_zone_entry_count().

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def get_active_track_ids(self, camera_id: str) -> set[int]:
members = self._r.smembers(self._active_key(camera_id))
result: set[int] = set()
for m in members:
events: list[TrackEvent] = []
for raw in raw_list:
🧰 Tools
🪛 GitHub Actions: Phase 3 — Memory Tests / 0_test.txt

[error] 352-352: ruff check (F841): Local variable result is assigned to but never used.

🪛 GitHub Actions: Phase 3 — Memory Tests / test

[error] 352-352: Ruff (F841): Local variable result is assigned to but never used.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/memory/memory.py` around lines 350 - 353, A newly inserted
get_active_track_ids definition was placed in the middle of get_sequence,
truncating get_sequence after raw_list, duplicating get_active_track_ids later,
and calling self._active_key(camera_id) even though _active_key() takes no
arguments; to fix, remove the misplaced duplicate method so get_sequence retains
its full body (including use of raw_list), keep a single get_active_track_ids
implementation positioned below get_zone_entry_count, and update any
_active_key(...) calls to call _active_key() with no arguments; reference
get_sequence, get_active_track_ids, get_zone_entry_count, raw_list, and
_active_key when making the changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Issue] — Add configurable max_age per zone

2 participants