|
| 1 | +# GitHub Copilot Metrics Gaps — Changes Documentation |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +This document describes the gaps identified between the DevLake `gh-copilot` plugin and the |
| 6 | +current GitHub Copilot Metrics API, and the changes made to close those gaps. All changes |
| 7 | +target per-user metrics exposure, correlation data, and full API field parity. |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +## Gap Analysis Summary |
| 12 | + |
| 13 | +The GitHub Copilot Metrics API (new report-download API, replacing the deprecated `/copilot/metrics` |
| 14 | +inline endpoint sunset on April 2, 2026) exposes significantly more data than the DevLake plugin |
| 15 | +was capturing. The gaps fell into five categories: |
| 16 | + |
| 17 | +| Category | Gap Description | Impact | |
| 18 | +|---|---|---| |
| 19 | +| **Enterprise/Org Daily Metrics** | Missing CLI user counts, code review user counts, chat panel modes, expanded PR metrics, CLI breakdown | Cannot track CLI adoption, code review usage, chat mode distribution, or detailed PR impact | |
| 20 | +| **Per-User Daily Metrics** | Missing `used_cli`, `used_copilot_code_review_active/passive` flags and CLI breakdown | Cannot identify which users use CLI or code review features | |
| 21 | +| **User-Team Mapping** | Entirely missing — no collector or model for `user-teams-1-day` endpoint | Cannot correlate user metrics to teams for team-level dashboards | |
| 22 | +| **Seat Assignments** | Missing team assignment fields and user name/email | Cannot identify which team assigned a seat or show user display names | |
| 23 | +| **Pull Request Metrics** | Only 4 of 14 PR fields captured | Cannot track merged PRs, merge time, Copilot review suggestions, or copilot-authored merge rates | |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## Changes Made |
| 28 | + |
| 29 | +### 1. Enterprise/Org Daily Metrics Model (`enterprise_metrics.go`) |
| 30 | + |
| 31 | +**New embedded struct: `CopilotCliMetrics`** |
| 32 | +- `CliSessionCount` — Number of CLI sessions |
| 33 | +- `CliRequestCount` — Number of CLI requests |
| 34 | +- `CliPromptCount` — Number of CLI prompts |
| 35 | +- `CliOutputTokenSum` — Total output tokens from CLI |
| 36 | +- `CliPromptTokenSum` — Total prompt tokens from CLI |
| 37 | + |
| 38 | +**New fields on `GhCopilotEnterpriseDailyMetrics`:** |
| 39 | + |
| 40 | +| Field | Type | API Source | Description | |
| 41 | +|---|---|---|---| |
| 42 | +| `DailyActiveCliUsers` | int | `daily_active_cli_users` | Daily active CLI users | |
| 43 | +| `DailyActiveCopilotCodeReviewUsers` | int | `daily_active_copilot_code_review_users` | Users actively using code review | |
| 44 | +| `DailyPassiveCopilotCodeReviewUsers` | int | `daily_passive_copilot_code_review_users` | Users passively receiving code review | |
| 45 | +| `WeeklyActiveCopilotCodeReviewUsers` | int | `weekly_active_copilot_code_review_users` | 7-day trailing active code review users | |
| 46 | +| `WeeklyPassiveCopilotCodeReviewUsers` | int | `weekly_passive_copilot_code_review_users` | 7-day trailing passive code review users | |
| 47 | +| `MonthlyActiveCopilotCodeReviewUsers` | int | `monthly_active_copilot_code_review_users` | 28-day trailing active code review users | |
| 48 | +| `MonthlyPassiveCopilotCodeReviewUsers` | int | `monthly_passive_copilot_code_review_users` | 28-day trailing passive code review users | |
| 49 | +| `ChatPanelAgentMode` | int | `chat_panel_agent_mode` | Chat panel interactions in agent mode | |
| 50 | +| `ChatPanelAskMode` | int | `chat_panel_ask_mode` | Chat panel interactions in ask mode | |
| 51 | +| `ChatPanelCustomMode` | int | `chat_panel_custom_mode` | Chat panel interactions in custom mode | |
| 52 | +| `ChatPanelEditMode` | int | `chat_panel_edit_mode` | Chat panel interactions in edit mode | |
| 53 | +| `ChatPanelPlanMode` | int | `chat_panel_plan_mode` | Chat panel interactions in plan mode | |
| 54 | +| `ChatPanelUnknownMode` | int | `chat_panel_unknown_mode` | Chat panel interactions in unknown mode | |
| 55 | +| `PRTotalMerged` | int | `pull_requests.total_merged` | Total PRs merged | |
| 56 | +| `PRMedianMinutesToMerge` | float64 | `pull_requests.median_minutes_to_merge` | Median minutes to merge PRs | |
| 57 | +| `PRTotalSuggestions` | int | `pull_requests.total_suggestions` | Total PR review suggestions | |
| 58 | +| `PRTotalAppliedSuggestions` | int | `pull_requests.total_applied_suggestions` | Total applied PR suggestions | |
| 59 | +| `PRTotalMergedCreatedByCopilot` | int | `pull_requests.total_merged_created_by_copilot` | Merged PRs created by Copilot | |
| 60 | +| `PRTotalMergedReviewedByCopilot` | int | `pull_requests.total_merged_reviewed_by_copilot` | Merged PRs reviewed by Copilot | |
| 61 | +| `PRMedianMinToMergeCopilotAuthored` | float64 | `pull_requests.median_minutes_to_merge_copilot_authored` | Median merge time for Copilot-authored PRs | |
| 62 | +| `PRMedianMinToMergeCopilotReviewed` | float64 | `pull_requests.median_minutes_to_merge_copilot_reviewed` | Median merge time for Copilot-reviewed PRs | |
| 63 | +| `PRTotalCopilotSuggestions` | int | `pull_requests.total_copilot_suggestions` | Total Copilot review suggestions | |
| 64 | +| `PRTotalCopilotAppliedSuggestions` | int | `pull_requests.total_copilot_applied_suggestions` | Total Copilot applied suggestions | |
| 65 | +| `CopilotCliMetrics` (embedded) | struct | `totals_by_cli.*` | CLI session/request/prompt/token metrics | |
| 66 | + |
| 67 | +### 2. Per-User Daily Metrics Model (`user_metrics.go`) |
| 68 | + |
| 69 | +**New fields on `GhCopilotUserDailyMetrics`:** |
| 70 | + |
| 71 | +| Field | Type | API Source | Description | |
| 72 | +|---|---|---|---| |
| 73 | +| `UsedCli` | bool | `used_cli` | Whether user used Copilot CLI on this day | |
| 74 | +| `UsedCopilotCodeReviewActive` | bool | `used_copilot_code_review_active` | Whether user actively used code review | |
| 75 | +| `UsedCopilotCodeReviewPassive` | bool | `used_copilot_code_review_passive` | Whether user passively used code review | |
| 76 | +| `CopilotCliMetrics` (embedded) | struct | `totals_by_cli.*` | Per-user CLI session/request/prompt/token metrics | |
| 77 | + |
| 78 | +### 3. User-Team Mapping (NEW — `user_team.go`) |
| 79 | + |
| 80 | +**New model: `GhCopilotUserTeam`** (table: `_tool_copilot_user_teams`) |
| 81 | + |
| 82 | +This is an entirely new data source. The GitHub API `user-teams-1-day` endpoint returns which |
| 83 | +teams each user belongs to per day. This enables **team-level metrics aggregation** by joining |
| 84 | +with the per-user daily metrics tables. |
| 85 | + |
| 86 | +| Field | Type | API Source | Description | |
| 87 | +|---|---|---|---| |
| 88 | +| `ConnectionId` | uint64 | — | DevLake connection (PK) | |
| 89 | +| `ScopeId` | string | — | DevLake scope (PK) | |
| 90 | +| `Day` | time.Time | `day` | Date of the mapping (PK) | |
| 91 | +| `UserId` | int64 | `user_id` | GitHub user ID (PK) | |
| 92 | +| `TeamId` | int64 | `team_id` | GitHub team ID (PK) | |
| 93 | +| `UserLogin` | string | `user_login` | GitHub username | |
| 94 | +| `OrganizationId` | string | `organization_id` | Organization ID | |
| 95 | +| `EnterpriseId` | string | `enterprise_id` | Enterprise ID | |
| 96 | +| `TeamSlug` | string | `slug` | Team slug for display | |
| 97 | + |
| 98 | +**New collector:** `CollectUserTeams` — fetches from `user-teams-1-day` endpoint (JSONL format) |
| 99 | +**New extractor:** `ExtractUserTeams` — parses JSONL records into the model |
| 100 | + |
| 101 | +### 4. Seat Assignments (`seat.go`) |
| 102 | + |
| 103 | +**New fields on `GhCopilotSeat`:** |
| 104 | + |
| 105 | +| Field | Type | API Source | Description | |
| 106 | +|---|---|---|---| |
| 107 | +| `UserName` | string | `assignee.name` | User's display name | |
| 108 | +| `UserEmail` | string | `assignee.email` | User's email address | |
| 109 | +| `AssigningTeamId` | int64 | `assigning_team.id` | Team that assigned the Copilot seat | |
| 110 | +| `AssigningTeamName` | string | `assigning_team.name` | Team display name | |
| 111 | +| `AssigningTeamSlug` | string | `assigning_team.slug` | Team URL slug | |
| 112 | + |
| 113 | +### 5. Extractor Updates |
| 114 | + |
| 115 | +All extractors were updated to populate the new fields: |
| 116 | + |
| 117 | +- **`enterprise_metrics_extractor.go`** — Updated `enterpriseDayTotal` struct with new API fields; |
| 118 | + updated `pullRequestStats` from 4 to 14 fields; added `totalsByCli` struct; expanded extraction |
| 119 | + logic for all new enterprise-level fields. |
| 120 | +- **`metrics_extractor.go`** (org metrics) — Same expansion as enterprise extractor since org reports |
| 121 | + use the identical format. Updated seat response structs to include `copilotTeam` for team assignment. |
| 122 | +- **`user_metrics_extractor.go`** — Updated `userDailyReport` struct with 3 new boolean flags and |
| 123 | + CLI breakdown; expanded extraction logic. |
| 124 | +- **`seat_extractor.go`** — Updated to extract `UserName`, `UserEmail`, and `AssigningTeam` fields. |
| 125 | + |
| 126 | +### 6. Migration Script |
| 127 | + |
| 128 | +**New file:** `20260527_add_copilot_metrics_gaps.go` |
| 129 | + |
| 130 | +- Adds new columns to `_tool_copilot_enterprise_daily_metrics` (28 columns) |
| 131 | +- Adds new columns to `_tool_copilot_user_daily_metrics` (8 columns) |
| 132 | +- Adds new columns to `_tool_copilot_seats` (5 columns) |
| 133 | +- Creates new table `_tool_copilot_user_teams` |
| 134 | + |
| 135 | +### 7. Registration Updates |
| 136 | + |
| 137 | +- `models.go` — Added `GhCopilotUserTeam` to `GetTablesInfo()` |
| 138 | +- `register.go` — Added `CollectUserTeamsMeta` and `ExtractUserTeamsMeta` to subtask list |
| 139 | +- `subtasks.go` — Added `CollectUserTeamsMeta` and `ExtractUserTeamsMeta` definitions with dependencies |
| 140 | +- `models_test.go` — Updated `TestGetTablesInfo` to include the new table |
| 141 | +- `migrationscripts/register.go` — Added `addCopilotMetricsGaps` migration |
| 142 | + |
| 143 | +--- |
| 144 | + |
| 145 | +## Files Changed |
| 146 | + |
| 147 | +| File | Change Type | Description | |
| 148 | +|---|---|---| |
| 149 | +| `models/enterprise_metrics.go` | Modified | Added `CopilotCliMetrics` embedded struct; 28 new fields on enterprise model | |
| 150 | +| `models/user_metrics.go` | Modified | Added 3 boolean flags + CLI metrics embed to per-user model | |
| 151 | +| `models/seat.go` | Modified | Added 5 team/user detail fields | |
| 152 | +| `models/user_team.go` | **Created** | New user-team mapping model | |
| 153 | +| `models/models.go` | Modified | Registered `GhCopilotUserTeam` in `GetTablesInfo()` | |
| 154 | +| `models/models_test.go` | Modified | Updated table count assertion | |
| 155 | +| `models/migrationscripts/20260527_add_copilot_metrics_gaps.go` | **Created** | Migration for all schema changes | |
| 156 | +| `models/migrationscripts/register.go` | Modified | Registered new migration | |
| 157 | +| `tasks/enterprise_metrics_extractor.go` | Modified | Expanded structs and extraction for 28 new fields | |
| 158 | +| `tasks/metrics_extractor.go` | Modified | Expanded org extraction + seat response structs | |
| 159 | +| `tasks/user_metrics_extractor.go` | Modified | Added 3 flags + CLI breakdown extraction | |
| 160 | +| `tasks/seat_extractor.go` | Modified | Added team and user detail extraction | |
| 161 | +| `tasks/user_teams_collector.go` | **Created** | New collector for user-teams-1-day endpoint | |
| 162 | +| `tasks/user_teams_extractor.go` | **Created** | New extractor for user-team JSONL records | |
| 163 | +| `tasks/subtasks.go` | Modified | Added 2 new subtask metas | |
| 164 | +| `tasks/register.go` | Modified | Added 2 new subtasks to execution order | |
| 165 | + |
| 166 | +--- |
| 167 | + |
| 168 | +## Correlation Capabilities Enabled |
| 169 | + |
| 170 | +With these changes, the following per-user and cross-dimensional analyses become possible: |
| 171 | + |
| 172 | +1. **User → Team correlation**: Join `_tool_copilot_user_teams` with `_tool_copilot_user_daily_metrics` |
| 173 | + on `(day, user_id)` to compute team-level usage aggregations |
| 174 | +2. **CLI adoption tracking**: Filter users/days where `used_cli = true` or analyze CLI token usage |
| 175 | +3. **Code review adoption**: Track active vs passive code review usage per user per day |
| 176 | +4. **Chat mode analysis**: Understand distribution of agent/ask/edit/plan/custom modes |
| 177 | +5. **PR impact analysis**: Track Copilot's impact on merge velocity (`median_minutes_to_merge_copilot_authored` |
| 178 | + vs `median_minutes_to_merge`) and suggestion acceptance rates |
| 179 | +6. **Seat utilization by team**: Join seats with `assigning_team` data for team-level licensing analysis |
| 180 | +7. **User identity enrichment**: `user_name` and `user_email` on seats enable richer user profiles |
| 181 | + |
| 182 | +--- |
| 183 | + |
| 184 | +## API Endpoints Used |
| 185 | + |
| 186 | +| Endpoint | Existing/New | Purpose | |
| 187 | +|---|---|---| |
| 188 | +| `enterprises/{e}/copilot/metrics/reports/enterprise-1-day` | Existing | Enterprise daily aggregate metrics | |
| 189 | +| `orgs/{o}/copilot/metrics/reports/organization-1-day` | Existing | Org daily aggregate metrics | |
| 190 | +| `enterprises/{e}/copilot/metrics/reports/users-1-day` | Existing | Per-user daily metrics | |
| 191 | +| `orgs/{o}/copilot/metrics/reports/users-1-day` | Existing | Per-user daily metrics (org scope) | |
| 192 | +| `enterprises/{e}/copilot/metrics/reports/user-teams-1-day` | **New** | User-team mapping | |
| 193 | +| `orgs/{o}/copilot/metrics/reports/user-teams-1-day` | **New** | User-team mapping (org scope) | |
| 194 | +| `orgs/{o}/copilot/billing/seats` | Existing | Seat assignments (expanded fields) | |
| 195 | +| `enterprises/{e}/copilot/billing/seats` | Existing | Seat assignments (expanded fields) | |
| 196 | + |
| 197 | +--- |
| 198 | + |
| 199 | +## Testing |
| 200 | + |
| 201 | +- All existing unit tests pass (`go test ./plugins/gh-copilot/... -count=1`) |
| 202 | +- `TestGetTablesInfo` updated and passing with 19 tables |
| 203 | +- `go vet` clean |
| 204 | +- Build successful (`go build ./plugins/gh-copilot/...`) |
0 commit comments