fix(telemetry): operator door exclusions wiped by restart and telemetry sync — needs AUTO/MANUAL provenance #48
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#48
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?
📌 Problem Statement
door_records.exclude_from_rankingsis a single boolean with no provenance, so two different sources write the same bit and become indistinguishable:SENSORLESS_OPEN/SENSORLESS_JUMPEREDdoor is auto-excluded whensettings.filter_sensorlessis on (app/db/door_repository.py:68-74; defaultTrue,app/config.py:45).set_exclusion_sync/set_category_exclusion_sync(app/db/door_repository.py:441,:458).Because both write the same flag, the one rule that reads it —
elif category == "VERIFIED_SENSOR" and existing["exclude_from_rankings"] == 1: exclude_from_rankings = 0(door_repository.py:88-89), plus the startupUPDATE door_records SET exclude_from_rankings = 0 WHERE category = 'VERIFIED_SENSOR'(app/db/database.py:385) — is correct for one source and wrong for the other:VERIFIED_SENSOR(sensor recovered → re-enter rankings).The MANUAL-wipe is the live bug surfaced in the PR #45 review (operator exclusions do not persist). But the naive fix — deleting both resets — regresses the AUTO path: a sensorless door that recovers would then stay excluded forever, because nothing clears it.
🎯 Required Solution — add provenance, then split the recovery rule
Introduce an exclusion source so AUTO and MANUAL can be governed independently.
Schema (
app/db/database.py)exclusion_source TEXT DEFAULT ''todoor_records(values:'AUTO','MANUAL', or''when not excluded).CREATE TABLEblock and to the additivePRAGMA table_infomigration guard, following the existingis_tracked/tracking_statuspattern (database.py:72-87) so existing production DBs upgrade in place.exclude_from_rankings = 1rows get a source by category —VERIFIED_SENSOR→'MANUAL'(auto never excludes verified doors, so a currently-excluded verified door is operator intent and must be preserved),SENSORLESS_*→'AUTO'. Rows withexclude_from_rankings = 0→''.Write paths (
app/db/door_repository.py):68-74): when it setsexclude=1, also setexclusion_source='AUTO'.set_exclusion_sync(excluded=True): setexclusion_source='MANUAL';excluded=False: clear to''. Same forset_category_exclusion_sync.upsert_sync: carryexclusion_sourcethrough alongside the flag (read it in the door-record mapping and echo it on write) so routine syncs don't drop it.Recovery rule (replaces
door_repository.py:88-89anddatabase.py:385)VERIFIED_SENSORtransition, clear the exclusion only whenexclusion_source == 'AUTO'(exclude=0,source=''). LeaveMANUALuntouched.UPDATE; the per-door AUTO-recovery rule above covers legitimate re-entry without touching operator exclusions.Net invariants
MANUAL) exclusions persist across server restarts (init_db) and across all telemetry syncs.AUTO) sensorless exclusions still auto-clear when the door recovers toVERIFIED_SENSOR.Where this is resolved
Resolve inside PR #45. #45 already owns the exclusion-persistence work; folding the provenance model in there keeps the domain change in one place and one migration, rather than shipping the blanket deletion (which regresses AUTO recovery) and fixing it later. #45's plan item 5 ("Door Ranking Exclusion Invariant") should be updated to this provenance approach instead of deleting the two resets outright.
Related
✅ Acceptance Criteria
door_recordshas anexclusion_sourcecolumn, added via both theCREATE TABLEand the in-placePRAGMA table_infomigration; existing DBs upgrade without data loss.VERIFIED_SENSOR→MANUAL,SENSORLESS_*→AUTO) for currently-excluded rows.source='AUTO'; operatorset_exclusion_sync/set_category_exclusion_syncwritesource='MANUAL'.VERIFIED_SENSORtransition clears onlyAUTOexclusions;MANUALpersists.VERIFIED_SENSORdoor stays excluded acrossinit_db()(restart) and across a telemetryupsert_syncthat omits the flag.VERIFIED_SENSORre-enters rankings.UPDATE ... WHERE category = 'VERIFIED_SENSOR'anddoor_repository.py:88-89are removed, replaced by the source-aware rule.CONTEXT.md§2 documents the AUTO vs MANUAL exclusion sources and their lifecycle.gabogg referenced this issue2026-09-22 12:35:01 +00:00