refactor(occupancy): one query shape for counts-over-time; delete get_hourly_flow_distribution_async #58
Labels
No labels
blocked
bug
enhancement
high-priority
low-priority
needs-info
needs-triage
ready-for-agent
ready-for-human
referenced
research
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
gabogg/hikcentral#58
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Spun out of #35 during the grilling session of 2026-09-22. #35's fix (1) — adding the missing join — lands in the camera-group join cutover (phase 2). This issue is #35's fix (3), the structural half.
Problem
There are two query shapes for "counts over time", and they have already drifted once.
get_bucketed_cycle_flow_async(app/db/occupancy_repository.py:1471) has the camera join, theis_excluded = 0 AND is_active = 1filter, a direction split and bucket parameterisation.get_hourly_flow_distribution_async(:1391) has none of them — no join, no filter, a singleSUM(count)with no direction split, and it skips empty hours entirely, solen(rows)is "active hours", not 24:It is the sole input to trust rules R1 (temporal dispersion) and R2 (burst concentration) in
evaluate_cycle_integrity_async— so the engine deciding whether a cycle is trustworthy reads a different dataset from the one whose numbers get published.Why a second issue
Adding the join (phase 2) makes the two queries agree today. It does not stop them drifting again, because there are still two of them. #35 says it directly:
It was split out because phase 2 already carries a six-query cutover, a sync rewrite and a deck change; folding in a rewrite of the trust-rule input would widen the blast radius on a PR whose correctness is hard enough to review as is.
Note for the statistics deck
The deck's diurnal series needs 24 dense buckets split by direction, with occupancy and CI bounds per bucket (
DiurnalTimeseriesBucket,app/schemas/occupancy_models.py). It should be built onget_bucketed_cycle_flow_async, not by extending the unfiltered query.Acceptance criteria
get_bucketed_cycle_flow_async(bucket_seconds=3600).get_hourly_flow_distribution_asyncdeleted.🤖 Generated with Claude Code
Triage resolution — 2026-09-23
Waits on PR #54 (amended 2026-09-23). PR #54's scope narrowed: it now only gives
get_hourly_flow_distribution_asyncthe same join and filter as the KPI queries, and thefull camera-group join cutover moved to #62 (1:1 camera groups, ADR 0005 on #54). #58 still
waits on #54 because it removes the function #54 edits. Verify #54 has merged before starting.
This is a strict consolidation of the counts-over-time query, preserving trust
verdicts wherever the underlying datasets already agree. Any change to trust
semantics requires separate acceptance criteria and separate scope.
Acceptance:
get_bucketed_cycle_flow_async(bucket_seconds=3600)andget_hourly_flow_distribution_asyncis removed.before applying trust rules. Do not count direction rows as separate hours.
Do not pad to 24 hours before computing R1.
the sparse-hour meaning used by trust evaluation.
camera exclusion effects on KPI totals and trust-rule inputs. The camera-group
variant of this test follows #62.
Dependency amended (2026-09-23), following the pre-merge review of PR #63.
The body said this was blocked on "the camera-group join cutover in PR #54". That cutover moved to #62. PR #54 now only aligns
get_hourly_flow_distribution_asyncwith the KPI queries' join and filter. This issue still waits on #54, because it removes the function #54 edits, but the camera-group exclusion test can only be written after #62. The blocking paragraph and the test criterion above were updated to match, as was the triage record indocs/audit/issue-triage-2026-09-23.md.Implementation caveat from PR #54 (merged): window-end parity.
PR #54 aligned
get_hourly_flow_distribution_asyncwith the KPI queries on the window end:<= cycle_end.get_bucketed_cycle_flow_async, which this issue makes the sole trust-rule input, still ends at< ?. When you consolidate onto it, keep the trust input and the KPI totals on the same bound, otherwise an event stamped exactly atcycle_endis counted by one and not the other.In practice callers pass
cycle_end = reset - 0.001(orstart + 86400 - 0.001), so only the final millisecond differs. Buttests/test_trust_dataset_parity.pypins the parity, and it will fail if the bounds diverge. See also #66 item 2.gabogg referenced this issue2026-09-23 22:41:33 +00:00
gabogg referenced this issue2026-09-27 23:39:54 +00:00