feat: Decoupled Business Cycles (04:00 AM Reset), Baseline Offset Calibration & Transit Bleed Analytics #4
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!4
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/occupancy-calibration-bleed-and-analytics"
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
1. Architectural & Domain Problem Formulation
2. Implemented Features & Core Algorithms
\mathcal{W}_D = [T_{D, ext{reset}}, T_{D+1, ext{reset}})cleanly partitions pedestrian traffic into continuous commercial cycles without truncating late-night business hours across calendar midnight.ext{Offset} = N_{ ext{patrol}} - ( ext{Total IN} - ext{Total OUT})during post-closing quiet windows (03:30-04:30).\max(0, ext{IN} - ext{OUT})) and hourly bleed velocity.ho_{ ext{asym}} = ext{IN} / ext{OUT}$.
\bar{W} = \bar{L} / \lambda.POST /api/occupancy/calibrate-offset) and cycle configuration.docs/statistical_occupancy_models.md: Formal mathematical derivations, queueing theory, and error bounds.docs/bleed_and_calibration_guide.md: Standard Operating Procedures (SOP) for security staff and operations managers.3. Test Coverage
pytest -v).🔄 Additional Updates & Refinements Summary
Following further UX testing, operational feedback, and visual audits, the following key enhancements have been pushed to this branch:
1. 🔍 Interactive Metric Tooltips & Stacking Context Fix
z-indexso tooltips never render underneath adjacent cards or containers.2. 🏢 Establishment Name Dynamic Binding & Genericization
"")."HIKCENTRAL PROFESSIONAL") with a dynamic establishment heading (#header-venue-name) linked directly tolive.mall_name.3. 🎨 Schedule Card (Card 2) Layout Redesign
flex-col)."HOR...") and compressed status badges into distorted shapes. The new layout provides dedicated breathing room for the status badge and schedule hours.4. 📐 Ground-Truth Guard Count Definition Clarification
\\mathbb{E}[N]) in baseline calibration so perimeter/parking patrols that do not cross monitored counting zones do not artificially inflate the nocturnal baseline offset.5. 🌐 Fixed Language Toggle (
toggleLanguage) & Live Localized RefreshtoggleLanguage()function ini18n.jsto toggle between English (en) and Spanish (es).refreshLocalizedComponents()to automatically re-render the 12 occupancy telemetry cards upon language switch without requiring a page refresh.✅ Verification
pytest -vclean).🚪 Physical Access Control & Sensor Audit Enhancements
This branch incorporates heuristic classification for physical sensors vs auxiliary channels, periodic upstream state reconciliation with automated "Unjustified Closure" handling, and person identification retention in duration rankings:
1. 🧠 Sensor & Circuit Health Heuristics
VERIFIED_SENSOR): Monitored access doors with operational magnetic contact sensors displaying confirmed dynamic state transitions during accesses.SENSORLESS_OPEN): Access points where the sensor circuit is disconnected or broken (reports continuous OPEN with zero transitions over extended periods).SENSORLESS_JUMPERED): SEN terminal bridged to GND or static (reports static CLOSED continuously, even during access grants).MAGLOCK_ONLY): Auxiliary and utility relay channels operating purely via electromagnetic pulse timers without physical door frame contacts.OFFLINE): Unreachable controllers or disconnected devices.2. 👤 Person Name Retention on "Open Longest" Ranking List
personName,personRole,cardNo) from the active access cycle.👤 [Person Name]is displayed directly beside the door name, distinguishing human-authorized door openings from exit buttons or emergency releases.3. 🔄 Periodic Upstream Reconciliation & "Unjustified Closure" Detection
"Cierre no justificado por HikCentral (Sincronización)"(COMPLETED).4. ⚡ Live Activity Stream Sorting Priority
MAX(COALESCE(last_updated, 0), start_time_epoch) DESC. Any newly modified, alarmed, or reconciled cycle immediately surfaces to index 0 (top of the feed).✅ Verification
🧹 Database Sanitation & Test Isolation
Test Artifact Isolation & Cleanup
tests/conftest.pyusing isolated temporary SQLite instances, guaranteeing that automated test executions never leak test data into the runtime environment.⚔️ Adversarial Code Review: PR #4
Pull Request: #4: feat: Decoupled Business Cycles (04:00 AM Reset), Baseline Offset Calibration & Transit Bleed Analytics
Branch:
feat/occupancy-calibration-bleed-and-analytics➔masterReview Focus: Mathematical Rigor, Domain Architecture, API Schemas, Edge Cases, Concurrency, and Standards.
🎯 Executive Summary & Verdict
\bar{L}, nocturnal arrival rate dilution, and clamped working-hours bleed logic.ALTER TABLESQL synthesis, duplicated SQL repositories.-04:00timezone offset in Artemis event queries; sequential blocking HTTP queries during background monitor loop.Verdict: CHANGES REQUESTED (Blocker Issues Identified). While the PR introduces valuable domain capabilities, critical mathematical flaws in queueing metrics and API schema oversights must be resolved before merging into production.
🔬 In-Depth Adversarial Findings
🚩 1. Little's Law Average Occupancy (
\bar{L}) uses Discrete Event Count instead of Time-Weighted Riemann Integralapp/db/occupancy_repository.py(get_cycle_average_occupancy_async)The academic specification in
docs/statistical_occupancy_models.mddefines average facility occupancy as a continuous time integral:395912\bar{L} = \frac{1}{\Delta T} \int_{t_0}^{t_1} \mathcal{O}_{\text{est}}(s) , ds395912
However,
get_cycle_average_occupancy_asynccomputes an arithmetic mean over discrete event rows:\approx 100people.\frac{\sum_{i=1}^{100} i + 99}{101} = 50.9people (~50% calculation error).\Delta t_i = t_{i+1} - t_i:395912\bar{L} = \frac{1}{t_{\text{now}} - t_{\text{start}}} \sum_{i=0}^{N} L_i \cdot (t_{i+1} - t_i)395912
🚩 2. Dwell Time
\bar{W}Arrival Rate Diluted Across Closed Nocturnal Hoursapp/services/occupancy_service.py(get_live_occupancy_async)cycle_startbegins at04:00AM, but the commercial facility opens at10:00AM.At
11:00AM (1 hour into commercial operations),elapsed_minsis \text{ hours} = 420 \text{ min}$.If 210 patrons entered since opening, the active arrival rate is
\lambda = 210 / 60 = 3.5 \text{ people/min}.Instead, the code calculates
\lambda = 210 / 420 = 0.5 \text{ people/min}.Consequently,
\bar{W} = \bar{L} / \lambdais artificially magnified by \times$, pegging the calculation against the 240-minute clamp.\lambda_{\text{effective}}using active commercial hoursmin(now - open_epoch, now - cycle_start)or a rolling window.🚩 3. Transit Bleed Clamping Logic Suppresses Active Daytime Bleed
app/services/occupancy_service.py(get_live_occupancy_async)baseline_offset >= 0,footfall_bleedis forced to0.baseline_offset < 0,(today_in - today_out) - estimated_occupancymathematically simplifies to-baseline_offset(a static number).It never measures dynamic daytime unmonitored egress as described in the documentation.
🚩 4. Untyped Payload & Dropped
reasonin/calibrate-offsetapp/controllers/occupancy_controller.pyvsapp/schemas/occupancy_models.pyThe Pydantic model
OffsetCalibrationRequestwas defined withreason, but the controller usespayload: Optional[Dict[str, Any]] = Noneand drops thereasonattribute:payload: OffsetCalibrationRequestand passreason=payload.reason.🚩 5. Hardcoded
-04:00Timezone in Upstream Event Queryapp/services/door_service.py(reconcile_door_states_with_upstream_async)datetime.datetime.now()returns naive system local time. If the backend runs in UTC containers, formatting UTC time with-04:00creates a 4-hour forward shift, causing event queries to return 0 results and mistakenly marking valid door closures as "Cierre no justificado por HikCentral".🚩 6. Sequential Blocking Artemis HTTP Queries in Background Monitor
app/services/door_service.py&app/services/monitor_service.pyIn
reconcile_door_states_with_upstream_async, when multiple doors have state discrepancies, it sequentially awaits Artemis HTTP calls inside afor code, door in list(self.doors.items())loop, blocking the mainbackground_monitorloop for multiple seconds.doorIndexCodes: [...]in a single batch request.🚩 7. Frontend Falsy Numeric Coalescing Bug (
||vs??)app/static/js/app.jspatrol_guard_count === 0(unmanned facility),0 || 12yields12. Whenasymmetry_ratio === 0.0,0.0 || 1.0displays1.0x.live.patrol_guard_count ?? 12andlive.asymmetry_ratio ?? 1.0.💡 Recommended Action Plan
\bar{L}and align\lambdawith active operating hours.OffsetCalibrationRequestinoccupancy_controller.pyand forward the calibration reason to repository audit logs.||with nullish coalescing (??) acrossapp.js.🛠️ PR Review Feedback Addressed & Mathematical Enhancements
Thank you for the thorough, rigorous review. All requested changes have been addressed and validated:
1. 📐 Continuous Time-Weighted Riemann Integral for Little's Law (
\\bar{L})app/db/occupancy_repository.pywith a continuous time-weighted Riemann sum:2. ⏱️ Active Operating Hours Alignment for Arrival Rate (
\\lambda) & Dwell (\\bar{W})app/services/occupancy_service.py, effective arrival rate\\lambda_{\\text{effective}}is computed across active operational hours (effective_start_epoch = max(cycle_start, open_epoch)).3. 🔄 Dynamic Daytime & Nocturnal Transit Bleed Formulation
\\max(0, -\\beta)plus any unmonitored net egress deficits.\\max(0, (I_{\\text{cycle}} - E_{\\text{cycle}}) - N_{\\text{patrol}}).4. 🔒 Typed API Payload & Audit Forwarding for
/calibrate-offsetapp/controllers/occupancy_controller.pyto bind the typedOffsetCalibrationRequestPydantic model and forward thereasonfield directly to backend logs and database audits.5. 🌐 Dynamic ISO 8601 Timezone Formatting
app/services/door_service.pywith dynamic local timezone formatting (dt.astimezone().isoformat()), ensuring containerized UTC deployments query upstream OpenAPI without timezone skew.6. ⚡ Batch Upstream State Reconciliation
reconcile_door_states_with_upstream_asyncto batch all mismatched doors into a single upstream request, eliminating sequential network queries and keeping the background monitor loop non-blocking.7. 🎯 Frontend Numeric Coalescing (
??)||) with nullish coalescing (??) acrossapp/static/js/app.jsso falsy numeric zeros (0,0.0,0.0x) display accurately without reverting to fallback defaults.✅ Test Suite & Verification
pytest -vclean), including dedicated unit tests for continuous Riemann occupancy integration and operating hours dwell calculations.✅ Verification & Resolution of Adversarial Review Findings (Commit
57489fc)Audit completed for commit
57489fc. All reported issues have been addressed and verified against the automated test suite.📊 Verification Matrix
get_cycle_average_occupancy_asyncinapp/db/occupancy_repository.pyto use continuous time-weighted Riemann step integration:\bar{L} = \frac{1}{\Delta T} \int_{t_0}^{t_1} \mathcal{O}(t) dt.\lambda& Dwell $\bar{W}\lambdainapp/services/occupancy_service.pyto the active commercial window:effective_start_epoch = max(cycle_start, open_epoch).reasonfieldOffsetCalibrationRequestinapp/controllers/occupancy_controller.pyand propagatedreasonto backend audit logs.-04:00offset in Artemis ISO stringsformat_iso_local(dt)inapp/services/door_service.pyusing dynamic timezone-awaredt.astimezone().isoformat().doorIndexCodes: mismatched_codes) inapp/services/door_service.py.evaluated0as falsy (0.0tests/test_occupancy.py.🧪 Test Suite Results
All 55 unit, integration, and mathematical tests pass with 100% green status. The PR is clean, mathematically rigorous, and ready for merge.
Closed as all commits from
feat/occupancy-calibration-bleed-and-analyticswere incorporated intomastervia PR #5 (feat/empirical-door-tracking).Pull request closed