Skip to content

Commit d9699af

Browse files
committed
feat: add observed_seconds to DailyBucket and PublicHistoryDay models
1 parent b9b15ef commit d9699af

4 files changed

Lines changed: 15 additions & 3 deletions

File tree

packages/ai-horde-service-alerts/src/ai_horde_service_alerts/db/repositories/history.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class DailyBucket:
3636

3737
date: str # ISO YYYY-MM-DD
3838
status_level: int # 0 ok, 1 minor (degraded/unknown), 2 major (partial/down), 3 maintenance
39+
observed_seconds: int # elapsed/observable seconds in this day (86400 for past days, partial for today)
3940
operational_seconds: int
4041
degraded_seconds: int
4142
down_seconds: int
@@ -162,10 +163,13 @@ async def daily_buckets(
162163
if secs > 0 and STATUS_RANK[status] > STATUS_RANK[worst_status]:
163164
worst_status = status
164165
worst_level = _LEVEL_BY_STATUS[worst_status]
166+
observed_end = min(anchor, day_end)
167+
observed_seconds = max(0, int((observed_end - day_start).total_seconds()))
165168
buckets.append(
166169
DailyBucket(
167170
date=day_start.date().isoformat(),
168171
status_level=worst_level,
172+
observed_seconds=observed_seconds,
169173
operational_seconds=seconds[ComponentStatusValue.OPERATIONAL],
170174
degraded_seconds=seconds[ComponentStatusValue.DEGRADED],
171175
down_seconds=seconds[ComponentStatusValue.DOWN] + seconds[ComponentStatusValue.PARTIAL],
@@ -190,7 +194,10 @@ async def uptime_percent(
190194
buckets = await self.daily_buckets(component_id, days=days, now=now)
191195
operational = sum(b.operational_seconds for b in buckets)
192196
maintenance = sum(b.maintenance_seconds for b in buckets)
193-
non_maintenance = days * 86_400 - maintenance
197+
# Use elapsed/observable time, not days * 86400: the current day is only
198+
# partially elapsed, so counting its future remainder would understate uptime.
199+
observable = sum(b.observed_seconds for b in buckets)
200+
non_maintenance = observable - maintenance
194201
if non_maintenance <= 0:
195202
return None
196203
observed = operational + sum((b.degraded_seconds + b.down_seconds + b.unknown_seconds) for b in buckets)

packages/ai-horde-service-alerts/src/ai_horde_service_alerts/models/public.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ class PublicHistoryDay(BaseModel):
130130
le=3,
131131
description="0 ok | 1 minor (degraded/unknown) | 2 major (partial/down) | 3 maintenance.",
132132
)
133+
observed_seconds: int = Field(
134+
description="Elapsed/observable seconds in this day: 86400 for past days, partial for today. "
135+
"Normalize the bar against this rather than assuming a full 86400-second day.",
136+
)
133137
operational_seconds: int
134138
degraded_seconds: int
135139
down_seconds: int

packages/ai-horde-service-alerts/src/ai_horde_service_alerts/services/projections.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ def history_response(
148148
PublicHistoryDay(
149149
date=b.date,
150150
status_level=b.status_level,
151+
observed_seconds=b.observed_seconds,
151152
operational_seconds=b.operational_seconds,
152153
degraded_seconds=b.degraded_seconds,
153154
down_seconds=b.down_seconds,

uv.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)