fix: restore default people-flow queue thresholds
This commit is contained in:
@@ -92,7 +92,13 @@ class QueueWindowTracker:
|
||||
self.closed_states.append(state)
|
||||
del self.states[track_id]
|
||||
|
||||
def build_queue_metrics(self, window_start: datetime, window_end: datetime) -> dict:
|
||||
def build_queue_metrics(
|
||||
self,
|
||||
window_start: datetime,
|
||||
window_end: datetime,
|
||||
*,
|
||||
commit_queue_level: bool = True,
|
||||
) -> dict:
|
||||
totals: dict[int, int] = {}
|
||||
for state in self.closed_states:
|
||||
queue_seconds = state.window_queue_seconds(window_start, window_end)
|
||||
@@ -120,7 +126,8 @@ class QueueWindowTracker:
|
||||
)
|
||||
previous_queue_level = self.last_queue_level
|
||||
status_change = _queue_status_change(previous_queue_level, queue_level)
|
||||
self.last_queue_level = queue_level
|
||||
if commit_queue_level:
|
||||
self.last_queue_level = queue_level
|
||||
return {
|
||||
"queue_time_threshold_seconds": self.config.queue_time_threshold_seconds,
|
||||
"over_threshold_count": over_threshold_count,
|
||||
|
||||
@@ -46,3 +46,88 @@ def test_queue_window_tracker_builds_crowded_report():
|
||||
assert queue_metrics["previous_queue_level_label"] == ""
|
||||
assert queue_metrics["status_change"] == "initial"
|
||||
assert queue_metrics["status_change_label"] == "初始"
|
||||
|
||||
|
||||
def test_live_preview_does_not_overwrite_previous_finalized_queue_level():
|
||||
tracker = QueueWindowTracker(
|
||||
QueueConfig(
|
||||
queue_time_threshold_seconds=60,
|
||||
crowded_count_threshold=3,
|
||||
normal_count_threshold=2,
|
||||
pause_timeout_seconds=5,
|
||||
),
|
||||
pixel_area=(0, 0, 100, 100),
|
||||
)
|
||||
first_window_start = datetime(2026, 4, 15, 11, 0, tzinfo=TZ)
|
||||
first_window_end = datetime(2026, 4, 15, 11, 5, tzinfo=TZ)
|
||||
second_window_start = first_window_end
|
||||
second_window_preview = datetime(2026, 4, 15, 11, 7, tzinfo=TZ)
|
||||
second_window_end = datetime(2026, 4, 15, 11, 10, tzinfo=TZ)
|
||||
|
||||
normal_tracks = [
|
||||
TrackObservation(
|
||||
track_id=index, bbox=(0, 0, 10, 10), confidence=0.9, center=(10, 10)
|
||||
)
|
||||
for index in range(1, 4)
|
||||
]
|
||||
few_tracks = [
|
||||
TrackObservation(
|
||||
track_id=10, bbox=(0, 0, 10, 10), confidence=0.9, center=(10, 10)
|
||||
)
|
||||
]
|
||||
|
||||
tracker.observe(normal_tracks, first_window_start)
|
||||
tracker.observe(normal_tracks, first_window_end)
|
||||
first_metrics = tracker.build_queue_metrics(first_window_start, first_window_end)
|
||||
|
||||
assert first_metrics["queue_level"] == "normal"
|
||||
assert first_metrics["status_change"] == "initial"
|
||||
|
||||
tracker.reset()
|
||||
tracker.observe(few_tracks, second_window_start)
|
||||
tracker.observe([], second_window_preview)
|
||||
preview_metrics = tracker.build_queue_metrics(
|
||||
second_window_start,
|
||||
second_window_preview,
|
||||
commit_queue_level=False,
|
||||
)
|
||||
|
||||
assert preview_metrics["queue_level"] == "few"
|
||||
assert preview_metrics["previous_queue_level"] == "normal"
|
||||
assert preview_metrics["status_change"] == "queue_decreased"
|
||||
|
||||
final_metrics = tracker.build_queue_metrics(second_window_start, second_window_end)
|
||||
|
||||
assert final_metrics["queue_level"] == "few"
|
||||
assert final_metrics["previous_queue_level"] == "normal"
|
||||
assert final_metrics["status_change"] == "queue_decreased"
|
||||
|
||||
|
||||
def test_queue_level_is_normal_when_count_reaches_threshold():
|
||||
tracker = QueueWindowTracker(
|
||||
QueueConfig(
|
||||
queue_time_threshold_seconds=60,
|
||||
crowded_count_threshold=3,
|
||||
normal_count_threshold=2,
|
||||
pause_timeout_seconds=5,
|
||||
),
|
||||
pixel_area=(0, 0, 100, 100),
|
||||
)
|
||||
start = datetime(2026, 4, 15, 11, 0, tzinfo=TZ)
|
||||
end = datetime(2026, 4, 15, 11, 5, tzinfo=TZ)
|
||||
tracks = [
|
||||
TrackObservation(
|
||||
track_id=index, bbox=(0, 0, 10, 10), confidence=0.9, center=(10, 10)
|
||||
)
|
||||
for index in range(1, 4)
|
||||
]
|
||||
|
||||
tracker.observe(tracks, start)
|
||||
tracker.observe(tracks, start.replace(minute=2))
|
||||
tracker.observe([], end)
|
||||
|
||||
metrics = tracker.build_queue_metrics(start, end)
|
||||
|
||||
assert metrics["over_threshold_count"] == 3
|
||||
assert metrics["queue_level"] == "normal"
|
||||
assert metrics["queue_level_label"] == "人数正常"
|
||||
|
||||
@@ -2,64 +2,33 @@
|
||||
|
||||
## Checklist
|
||||
|
||||
- [x] Audit the current `.11` deployment state, image tags, and runtime container diffs.
|
||||
- [x] Identify the minimal release payload: pushed images, compose/env/config assets, weights, and runtime-added files not present in the base images.
|
||||
- [x] Push the `.11` images to `ota.zhengxinshipin.com:5443` with stable release tags.
|
||||
- [x] Build a ZIP bundle containing compose files and all required non-image runtime assets.
|
||||
- [x] Publish the ZIP bundle and an install script under `/var/www/html/ai_deploy` on `10.8.0.1`.
|
||||
- [x] Verify the published artifacts are downloadable and the install flow is internally consistent.
|
||||
- [x] Verify the local managed config files already match the requested webhook, 30-minute window, 5-minute queue threshold, and `2-5 normal / >5 crowded` defaults.
|
||||
- [x] Restore any queue-level code or tests that still reflect the temporary `>= threshold` crowded behavior.
|
||||
- [x] Run targeted validation for the touched queue-analytics logic.
|
||||
- [x] Update `tasks/todo.md` review evidence and create a scoped git commit containing only the intended files.
|
||||
|
||||
## Scope And Risks
|
||||
|
||||
- Scope: publish the current managed-portal deployment that is running on `10.8.0.11` by pushing its images to `ota.zhengxinshipin.com:5443`, generating a downloadable install script on `10.8.0.1`, and uploading a ZIP bundle with compose/runtime assets required for the stack to run correctly elsewhere.
|
||||
- Expected touch points: remote Docker images on `.11`, runtime asset directories under `managed/`, deployment compose/env files under `deploy/`, and installer artifacts on `/var/www/html/ai_deploy` on `10.8.0.1`.
|
||||
- Risk: the running `.11` containers use local `:dev` images and also contain runtime-added files such as `lap` inside `people-flow-project`; pushing only the local images will not fully reproduce the running state unless those extras are separately bundled or the install path reapplies them.
|
||||
- Risk: required assets may live outside the image as mounted files, especially configs, outputs, weights, and managed data. Missing any of these will produce an install that starts but does not behave like `.11`.
|
||||
- Risk: registry push may require credentials that are not currently cached for user `xiaozheng`; confirm push access before finalizing the artifact layout.
|
||||
- Scope: restore repository-local managed-service defaults so webhook delivery remains enabled, people-flow reporting flushes every 30 minutes, queue threshold is 5 minutes, fewer than 2 qualifying people means `人少`, `2-5` means `人数正常`, and more than `5` means `人多`, then commit the relevant changes.
|
||||
- Expected touch points: `managed/people_flow_project/src/people_flow/queue_analytics.py`, `managed/people_flow_project/tests/test_queue_analytics.py`, and verification of local config files under `managed/*/config/` plus any generated OTA test output that should remain aligned.
|
||||
- Risk: the worktree already contains unrelated modified and untracked files, so the commit must be scoped carefully to avoid pulling in unrelated work.
|
||||
- Risk: `store_dwell_alert` still has a separate queue-level implementation with the same `>` crowded comparison, but the user asked specifically to restore local config defaults plus "the code"; if we only revert people-flow logic, we should be explicit about any remaining asymmetry.
|
||||
|
||||
## Validation Intent
|
||||
|
||||
- Prove the exact `.11` images were retagged and pushed to `ota.zhengxinshipin.com:5443`.
|
||||
- Prove the ZIP bundle includes compose/env/config/runtime assets needed by the current `.11` deployment.
|
||||
- Prove the install script on `10.8.0.1` references the published URLs, downloads the ZIP, unpacks it, and pulls the registry images expected by the compose file.
|
||||
- Prove the local config files already encode `window_seconds: 1800`, `queue_time_threshold_seconds: 300`, `crowded_count_threshold: 5`, `normal_count_threshold: 2`, and webhook URLs.
|
||||
- Prove the restored queue-level comparison classifies `over_threshold_count == 5` as `normal` and only `>5` as `crowded`.
|
||||
|
||||
## Review
|
||||
|
||||
- Status: completed.
|
||||
- Result: published the current `.11` managed-portal stack as release `20260513-330373b-11`, including pushed registry images, a runtime-asset ZIP, and an install script under `/var/www/html/ai_deploy` on `10.8.0.1`.
|
||||
- Release payload:
|
||||
- Registry images pushed to `ota.zhengxinshipin.com:5443`:
|
||||
- `managed-portal:20260513-330373b-11`
|
||||
- `managed-portal-web:20260513-330373b-11`
|
||||
- `people-flow-project:20260513-330373b-11`
|
||||
- `store-dwell-alert:20260513-330373b-11`
|
||||
- ZIP bundle: `/var/www/html/ai_deploy/managed-portal-20260513-330373b-11.zip`
|
||||
- Installer script: `/var/www/html/ai_deploy/install-managed-portal-20260513-330373b-11.sh`
|
||||
- Latest symlinks:
|
||||
- `/var/www/html/ai_deploy/managed-portal-latest.zip`
|
||||
- `/var/www/html/ai_deploy/install-managed-portal-latest.sh`
|
||||
- ZIP contents include:
|
||||
- `deploy/docker-compose.yml`
|
||||
- `deploy/docker-compose.ota-release.yml`
|
||||
- `deploy/managed-portal.release.env`
|
||||
- `deploy/Dockerfile.runtime-overlay`
|
||||
- `managed_services.yaml`
|
||||
- mounted runtime assets from `.11`: people-flow config/outputs/weights and store-dwell config/data
|
||||
- runtime overlays extracted from running containers for `lap` in both Python services and `/app/logs/events.jsonl` from `store-dwell-alert`
|
||||
- Verification:
|
||||
- Registry push succeeded for all four images. Observed repo digests:
|
||||
- `managed-portal@sha256:589f699edce8271c80516030eae81abed95d8e62804976955eb86bf211d98f4e`
|
||||
- `managed-portal-web@sha256:f2e99c4745a3c16118a74084585f0a455e4f5295d9eb4cbabf2689b841966d9b`
|
||||
- `people-flow-project@sha256:963ecd41ee8a3f986c581b5330ce7163614571427711d524b936f05c3e84ec96`
|
||||
- `store-dwell-alert@sha256:d324cb2653ef25f6984a12b0cfa92064bf2c86b2946462001d14d254818d243d`
|
||||
- Source and published ZIP sizes match exactly: `1261636056` bytes on `.11` and `.1`.
|
||||
- HTTP validation succeeded:
|
||||
- `http://10.8.0.1/ai_deploy/managed-portal-20260513-330373b-11.zip` => `200 OK`, `Content-Length: 1261636056`
|
||||
- `http://10.8.0.1/ai_deploy/install-managed-portal-20260513-330373b-11.sh` => `200 OK`
|
||||
- ZIP content validation succeeded both at the source and after upload, including `release-manifest.env`, `deploy/docker-compose.ota-release.yml`, and runtime overlay files under `runtime-overlays/.../lap/...`.
|
||||
- Local release asset validation passed:
|
||||
- `sh -n deploy/install-managed-portal-ota.sh`
|
||||
- compose config expansion for `deploy/docker-compose.ota-release.yml` with the `.11` env file and placeholder image refs
|
||||
- Residual risk:
|
||||
- The published installer was validated for syntax and asset consistency, but it was not executed end-to-end on a fresh target host in this task.
|
||||
- The bundle intentionally excludes ephemeral `/tmp`, `/run`, and NVIDIA runtime-injected host libraries; reproducing GPU runtime behavior still depends on the target host having a working NVIDIA container runtime when `gpus: all` is used.
|
||||
- Config verification: local repository configs already matched the requested defaults before code edits.
|
||||
- `managed/people_flow_project/config/local.yaml`: `webhook.url` points to managed queue, `rtsp.window_seconds=1800`, `queue_time_threshold_seconds=300`, `crowded_count_threshold=5`, `normal_count_threshold=2`.
|
||||
- `managed/store_dwell_alert/config/local.yaml`: `webhook.url` points to managed queue, `queue_time_threshold_seconds=300`, `crowded_count_threshold=5`, `normal_count_threshold=2`.
|
||||
- Generated OTA test configs under `test_output/managed-portal-test-ota/managed/.../config/local.yaml` were already aligned with the same values.
|
||||
- Code restoration: reverted `managed/people_flow_project/src/people_flow/queue_analytics.py` so `queue_level="crowded"` now requires `over_threshold_count > crowded_count_threshold`, which restores the requested `2-5 normal / >5 crowded` behavior.
|
||||
- Test restoration: updated `managed/people_flow_project/tests/test_queue_analytics.py` so the preview-state coverage remains intact while the boundary assertion now proves `over_threshold_count == crowded_count_threshold` stays `normal`.
|
||||
- Validation:
|
||||
- `PYTHONPATH=. pytest tests/test_queue_analytics.py` in `managed/people_flow_project`
|
||||
- Result: `3 passed in 0.03s`
|
||||
- Commit scope note: only `managed/people_flow_project/src/people_flow/queue_analytics.py`, `managed/people_flow_project/tests/test_queue_analytics.py`, and `tasks/todo.md` should be committed for this task because the worktree contains unrelated modified and untracked files.
|
||||
|
||||
Reference in New Issue
Block a user