Skip to content

Commit cfffbd2

Browse files
authored
Merge pull request #46 from VectorInstitute/bug_fixes
Fix bugs to compute active hours
2 parents f0c6c64 + 0243938 commit cfffbd2

File tree

2 files changed

+44
-4
lines changed

2 files changed

+44
-4
lines changed

scripts/collect_coder_analytics.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,10 @@ def fetch_workspaces(
330330
workspace["total_usage_hours"] = round(total_usage_hours, 2)
331331

332332
# Add active hours from activity insights
333+
# NOTE: active_hours is per-USER (not per-workspace) and includes
334+
# ALL TIME activity. Users with multiple workspaces will have the
335+
# same value on each workspace. The frontend aggregation logic
336+
# handles this correctly by counting each user once.
333337
owner_name = workspace.get("owner_name", "").lower()
334338
workspace["active_hours"] = activity_map.get(owner_name, 0.0)
335339

services/analytics/lib/metrics.ts

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,42 @@ function getWorkspaceActiveHours(workspace: CoderWorkspace): number {
9696
return 0;
9797
}
9898

99+
/**
100+
* Calculate total active hours for a group of workspaces, ensuring logical consistency
101+
*
102+
* Active hours from Insights API are per-user across all time (including deleted workspaces).
103+
* To ensure active hours ≤ total hours, we cap each user's active hours at their total workspace hours.
104+
*
105+
* @param workspaces - Array of workspace metrics to aggregate
106+
* @returns Total active hours across all unique users, capped at their workspace totals
107+
*/
108+
function calculateTotalActiveHours(workspaces: WorkspaceMetrics[]): number {
109+
// Track active hours and total hours per unique user
110+
const userActiveHours = new Map<string, number>();
111+
const userTotalHours = new Map<string, number>();
112+
113+
workspaces.forEach((workspace) => {
114+
const user = workspace.owner_github_handle;
115+
116+
// Active hours are per-user (same across all their workspaces), so take max
117+
const existingActive = userActiveHours.get(user) || 0;
118+
userActiveHours.set(user, Math.max(existingActive, workspace.active_hours));
119+
120+
// Total hours are per-workspace, so sum them up
121+
const existingTotal = userTotalHours.get(user) || 0;
122+
userTotalHours.set(user, existingTotal + workspace.workspace_hours);
123+
});
124+
125+
// Cap each user's active hours at their total hours (handles deleted workspaces)
126+
let totalActive = 0;
127+
userActiveHours.forEach((activeHours, user) => {
128+
const totalHours = userTotalHours.get(user) || 0;
129+
totalActive += Math.min(activeHours, totalHours);
130+
});
131+
132+
return totalActive;
133+
}
134+
99135
/**
100136
* Classify activity status based on days since last active
101137
*/
@@ -278,8 +314,8 @@ export function aggregateByTeam(workspaces: WorkspaceMetrics[]): TeamMetrics[] {
278314
// Total workspace hours (sum of all workspace lifetime hours)
279315
const totalWorkspaceHours = teamWorkspaces.reduce((sum, w) => sum + w.workspace_hours, 0);
280316

281-
// Total active hours (sum of actual interaction hours from Insights API)
282-
const totalActiveHours = teamWorkspaces.reduce((sum, w) => sum + w.active_hours, 0);
317+
// Total active hours (aggregated correctly per-user, capped at their workspace totals)
318+
const totalActiveHours = calculateTotalActiveHours(teamWorkspaces);
283319

284320
// Average workspace hours
285321
const avgWorkspaceHours =
@@ -432,8 +468,8 @@ export function calculateTemplateMetrics(
432468
// Total workspace hours (sum of all workspace lifetime hours)
433469
const totalWorkspaceHours = templateWorkspaces.reduce((sum, w) => sum + w.workspace_hours, 0);
434470

435-
// Total active hours (sum of actual interaction hours from Insights API)
436-
const totalActiveHours = templateWorkspaces.reduce((sum, w) => sum + w.active_hours, 0);
471+
// Total active hours (aggregated correctly per-user, capped at their workspace totals)
472+
const totalActiveHours = calculateTotalActiveHours(templateWorkspaces);
437473

438474
// Average workspace hours
439475
const avgWorkspaceHours =

0 commit comments

Comments
 (0)