feat(doors): implement empirical observational door telemetry and tracking classification #5
No reviewers
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!5
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/empirical-door-tracking"
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?
🚪 Summary of Changes
Context & Motivation
Rather than relying solely on upstream static snapshot status (
doorState: 0..4) which can produce misleading metrics due to uninstrumented dummy channels or dry loops, this pull request implements an Empirical Observational Telemetry Model.The system actively observes and scores door telemetry over time—tracking verified physical transitions, access credential events, push button grants, and magnetic lock feedback—to partition physical doors into verified active channels (Tracked) versus dormant or uninstrumented channels (Untracked).
🔑 Key Architecture & Implementation Details
1. 📊 Domain Classification & Confidence Scoring
TrackingStatusenum (TRACKED,UNTRACKED,OFFLINE).classify_empirical_tracking(...)inapp/services/door_classifier.py:TRACKED: Doors with observed physical state transitions (N > 0) or confirmed active access cycles receive high empirical confidence scores (0.60 \dots 1.00).UNTRACKED: Unobserved static channels, utility loops, and uninstrumented channels are identified and isolated without polluting operational metrics.OFFLINE: Disconnected or unreachable controllers/channels are flagged cleanly.2. ⚡ Dynamic Real-Time Promotion
app/services/door_service.py, whenever a live state transition occurs during polling synchronization or a webhook event (DOOR_OPEN,DOOR_CLOSE,CARD_PASS) is ingested, the door is promoted toTRACKEDwithlast_observed_activityrecorded.3. 🗄️ Database & Schema Persistence
app/db/database.pywith automated migration checks for:is_tracked(INTEGER DEFAULT 0)tracking_status(TEXT DEFAULT 'UNTRACKED')tracking_confidence(REAL DEFAULT 0.0)tracking_reason(TEXT DEFAULT '')last_observed_activity(REAL)app/db/door_repository.pyto persist and read empirical columns across sync and async operations.4. 📈 Aggregation & Status Partitions
DoorOverviewResponseandget_door_overview()to deliver:tracked_doors_count,untracked_doors_counttracked_open_count,tracked_closed_countuntracked_open_count,untracked_closed_counttracked_doors,untracked_doorsarrays5. 🧹 Documentation & Artifacts Maintenance
docs/REFACTOR_PR_DESCRIPTION.md) to maintain a clean codebase context.🧪 Test Suite & Verification
pytestclean):tests/test_domain.py.tests/test_doors_reconciliation.py.PR Review & Architectural Evaluation Report:
feat/empirical-door-trackingTarget PR:
feat/empirical-door-trackingvsmaster(commit44e4d5b)Evaluation Verdict: REQUEST_CHANGES ❌ / DO NOT MERGE
Victory Audit: Confirmed & Independently Verified
Executive Summary
An exhaustive, multi-perspective code review and architectural evaluation was conducted across domain modeling, code structure, concurrency, database integrity, and test coverage.
While
pytestpasses 100% of the existing 64 tests, our adversarial evaluation and empirical stress tests revealed 3 Critical state machine and database defects, 2 Critical concurrency/event-loop starvation bottlenecks, 1 Forensic test-masking integrity issue, and 5 Major architectural flaws.Evaluation Scorecard
DoorRepository, state machine invariant violations inDoorStateManageron network disconnects.🔴 Critical Severity Findings (Merge Blockers)
[C1] State Machine Invariant Violation: Network Disconnects Misclassified as Physical Transitions
app/services/door_service.py:370-383,app/services/door_service.py:465-478CONTEXT.md§ DoorState & SensorCategoryif prev_state is not None and prev_state != new_state:evaluates toTruewhen a door goes offline (doorState = 4) or switches command locks (1 <-> 3).VERIFIED_SENSOR, assignedTRACKEDstatus with 1.0 confidence, and generate phantomDOOR_CLOSEaccess records upon reconnection (4 -> 1).[C2] Persistence Layer Domain Mutation & Empirical State Demotion
app/db/door_repository.py:56-131,app/db/door_repository.py:164-239DoorRepository.upsert_sync/asyncexecutes domain logic (incrementing transitions, forcingTRACKED).UNTRACKED,0.0,"") when callers pass dictionaries without tracking keys.[C3] Event Loop Starvation in 1.0s Background Polling Worker
app/services/door_service.py:384sync_doors_async()runs on a 1.0-second interval but invokes synchronousdoor_repo.upsert_sync()inside a 500-door iteration loop, executing hundreds of blocking SQLite transactions directly on the asyncio event loop.door_repo.upsert_async()or batch writes offloaded viaasyncio.to_thread().[C4] Async Polling & Webhook Race Condition
app/services/door_service.py:304-386,app/services/door_service.py:489-554sync_doors_async(), execution yields duringawait artemis.request_async(...). Webhooks arriving during this await update the in-memory state. When the stale polling response resumes, it detects a false transition, triggering spuriousDOOR_CLOSEevents.event_time > last_observed_activity) or synchronize with anasyncio.Lock.[C5] Forensic Integrity Violation: Masked Test & Unused Facade
tests/test_domain.py:191-203,app/db/door_repository.py:148-251test_door_classifier_empirical_untracked_utilityusednew_state=OPEN, causing early return at line 60 and completely bypassing theelif is_utility:branch at line 67. The test passed only due to accidental substring overlap.upsert_asyncwas updated and tested intest_concurrency.pybut is dead code in production (never called indoor_service.py).upsert_asyncinto async background loops.🟠 Major Severity Findings
door_service.py:628): Sensorless doors forced toTRACKEDduring access session reconciliation.app/controllers/door_controller.py:21-27):get_sensor_diagnostics()executes synchronous HTTP calls in anasync defFastAPI route.door_service.py:580, 744, 804): Background workers open and close up to 1,500 fresh SQLite connections every second.door_service.py:516-538): Card scan rejections increment transitions and promote channels toTRACKED.door_service.py:734-750): Offline doors are lumped intountracked_doors, causing inventory discrepancies.Recommended Next Steps
app/services/door_service.py.app/db/door_repository.pyto coalesce tracking metadata and remove domain logic.sync_doors_async()to useupsert_async()with batched database transactions.tests/test_domain.py.🛠️ PR Review Feedback Remediated & State Machine Invariants Verified
Thank you for the rigorous, comprehensive review. All Critical findings (C1–C5) and Moderate findings (M1–M5) have been addressed, refactored, and verified with 70 passing automated tests.
🏛️ Critical Architectural & Invariant Remediations
1. [C1] State Machine Transition Invariants Guarded
PHYSICAL_OPEN_STATES = (0, 2)andPHYSICAL_CLOSED_STATES = (1, 3).sync_doors_async()andhandle_webhook_event()strictly require transitions between physical open and physical closed states. Controller disconnections/reconnections (4 <-> 1), offline state transitions, and administrative lock toggles (1 <-> 3) do not increment physical transitions or promote uninstrumented doors toVERIFIED_SENSOR/TRACKED.2. [C2] Separation of Concerns & SQLite Row Coalescing
door_repository.py.COALESCElogic in_prepare_record_values, preserving existing empirical tracking status, confidence scores, and transition counts without risk of field regression.3. [C3 & M3] Asynchronous Batch Persistence (
executemany)upsert_batch_syncandupsert_batch_asyncindoor_repository.pyutilizing a single database connection and transaction.4. [C4] Polling vs. Real-Time Webhook Concurrency Guard
poll_start_timebefore querying upstream Artemis.last_observed_activity > poll_start_time), the live in-memory state is preserved, preventing stale polling snapshots from overwriting fresh event data.5. [C5] Forensic Integrity in Classification & Unmasked Tests
classify_empirical_tracking, utility door classification (is_utility) is evaluated strictly before open-loop state checks.test_door_classifier_empirical_untracked_utilityto usenew_state=CLOSEDto ensure the utility classification path is directly exercised, and added a distinct unit test for uninstrumented open-loop channels.⚙️ Moderate Improvements Remediated
6. [M1] Invariant-Preserving Upstream Closure Reconciliation
reconcile_door_states_with_upstream_async(), reconciling unjustified open states toCLOSEDmaintains existing tracking categorization and confidence rather than forcibly promoting uninstrumented doors to verified channels.7. [M2] Asynchronous Diagnostics Route
audit_sensors_vs_maglocks_async()indoor_service.pyand properly awaited it indoor_controller.py, eliminating synchronous blocking inside async FastAPI request handlers.8. [M4] Webhook Non-State Event Filtering
handle_webhook_event(), non-state access events (e.g. invalid scans or alarms without door movement) update the activity timestamp without incrementing physical transitions or toggling open/closed state.9. [M5] Partition Arithmetic Consistency
get_door_overview(), partition arithmetic strictly separates doors into:offline_doors:is_offline == Truetracked_doors:is_tracked == True and not is_offlineuntracked_doors:is_tracked == False and not is_offlinetracked_doors_count + untracked_doors_count + offline_count == total_doorsholds true with zero category overlap.✅ Test Suite Verification
pytest -v).