From d06f5bd2f2f266e6ffed649f6595262b60a792f5 Mon Sep 17 00:00:00 2001 From: Adam Moussa Date: Mon, 13 Jul 2026 13:16:30 -0400 Subject: [PATCH] fix(sla-monitor): count only business hours in SLA elapsed-time calc _business_minutes_elapsed clamped each weekday span to midnight instead of BH_END, and never applied BH_START, so overnight hours (17:00-08:00) were counted as business time. BH_START/BH_END were defined but unused in the calculation. A ticket opened Fri 16:00 and evaluated Mon 10:00 scored 1080 min instead of the correct 180 min (6x overcount), flipping a tier-1 breach into a false tier-2 page. Clamp each weekday to the [BH_START, BH_END) window and only accrue the overlap with [since, now); weekends remain excluded. Holidays are still unhandled (pre-existing, separate gap). Found by the daily scanner (agentic, CWE-440); proof-or-kill confirmed. --- src/sla_monitor/app.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/sla_monitor/app.py b/src/sla_monitor/app.py index d4f0657..a5ac69e 100644 --- a/src/sla_monitor/app.py +++ b/src/sla_monitor/app.py @@ -185,11 +185,17 @@ def _business_minutes_elapsed(since_utc, now_utc): while current < now: if current.weekday() < 5: - end_of_day = (current + timedelta(days=1)).replace( - hour=0, minute=0, second=0, microsecond=0 + # Count only the business-hours window [BH_START, BH_END) on this + # weekday. Clamp the day's span to the portion that overlaps + # [current, now); overnight hours (BH_END..next BH_START) are excluded. + day_start = current.replace( + hour=BH_START, minute=0, second=0, microsecond=0 ) - day_end = min(end_of_day, now) - total += (day_end - current).total_seconds() / 60 + day_close = current.replace(hour=BH_END, minute=0, second=0, microsecond=0) + span_start = max(current, day_start) + span_end = min(day_close, now) + if span_end > span_start: + total += (span_end - span_start).total_seconds() / 60 current = (current + timedelta(days=1)).replace( hour=0, minute=0, second=0, microsecond=0