fix(calibration): per-cycle calibration log lookup can return a neighbouring cycle's log #127
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#127
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?
Split out of the #126 review (pass 1, Standards P2). It's inherited behaviour, not introduced by #126, but since #126 the daily series, hourly series and dayparts all read past-cycle calibration through this one lookup.
Problem
OccupancyRepository.get_calibration_log_for_cycle_async(date_str, start_epoch, end_epoch)picks "the" calibration log for a business cycle with:It can return another cycle's log:
timestamp_epochinside D+1's window. It is ranked first, so D+1 picks up D's exit multiplier and guard count.superseded_by, unlike the trusted-history and trust-verdict queries, which useis_current = 1 AND superseded_by IS NULL.Effect: a past day can be shown (occupancy, peak, dwell, dayparts) with the neighbouring day's k, which is against ADR 0006.
Proposal
cycle_date = ?and addsuperseded_by IS NULL.cycle_date, e.g.(cycle_date = ? OR ((cycle_date IS NULL OR cycle_date = '') AND timestamp_epoch BETWEEN ? AND ?)).cycle_dateis still found by its window.Related: #76 (which cycle a calibration window belongs to), #126 (shared
_cycle_exit_multiplier_async), ADR 0006.🤖 Generated with Claude Code
gabogg referenced this issue2026-09-26 01:41:04 +00:00
Related evidence from PR #227 review pass 2. The single-row calibration-log lookup uses an inclusive window end (
timestamp_epoch <= ?,occupancy_repository.py~3324), while the batched lookup excludes it (< p.end_epoch). A log stamped exactly at a cycle boundary therefore resolves to different cycles depending on which path reads it, which is this issue's neighbouring-cycle symptom. The statistics audit doc (line ~62) claims the two paths match; it should be corrected when this is fixed.