Team analytics ​
CodeLotse reports how reviews, triage, assignment suggestions and fixes work out for a team, and what the model calls cost. Analytics are team-level: there is no per-person view for anyone except the person themself, no ranking, no leaderboard and no per-person export.
Where to find it ​
| Screen | Who | Content |
|---|---|---|
| Analytics → Team metrics | Tenant admins | Whole tenant, a team (group of repositories) or one repository |
| Analytics → Costs | Tenant admins | Tokens, cost and prompt-cache hits for the tenant |
| Analytics → Teams | Tenant admins | Teams are groups of repositories; people are never assigned to teams |
| Analytics → Settings | Tenant admins | Minimum group size, personal metrics switch, budget alert thresholds |
| Analytics → My metrics | The person themself | Only when allowed (see below) |
| Repository Analytics tab | Everyone who can view the repository | Team metrics of that repository; costs for repository admins |
| Settings → Evaluation runs | Instance admins | Runs recorded with quavon eval full --record-db |
Every chart has a table alternative ("Show as table"). Values can be downloaded as CSV (format=csv).
Privacy ​
- Minimum group size (k). A point (period, and dimension value when split) is shown only when at least
kdistinct people contributed to it (default 5, configurable 5 to 50). Otherwise the point is hidden and never exported. Bots never count. The population is the authors of the pull requests or issues the events belong to; it is computed from the source tables at query time and never returned (no head counts are shown). - Admin-only wide scopes. Tenant and team scopes need
tenant:manage. Members see repositories they can view. - Differencing. Comparing overlapping scopes (tenant minus team, team A minus team B) can narrow a group. Each scope applies
kon its own, and the wide scopes are admin-only; the residual risk remains and should be covered by the works agreement. - Personal metrics (
/api/me/tenants/:tenantId/analytics) need the tenant switch Allow people to see their own metrics, the person's own opt-in in their assignment settings (people.individual_metrics_opt_in) and no team-only metrics (works-council mode or the tenant setting). They exclude repositories whose assignment policy sets team-only metrics. Nobody else, including tenant and instance admins, can read them. Users signed in through OIDC have no linked person and get 404. - Costs are not about people and are exempt from
k; they are only available to tenant or repository admins.
Metric dictionary ​
The period of an event is the UTC day of the timestamp named below. Weeks are ISO weeks starting on Monday; months are calendar months (UTC). Rates are numerator / denominator summed over the period.
| Metric | Definition | Day of | Population | Split by |
|---|---|---|---|---|
acted_on_rate | Findings whose feedback outcome is acted / findings with outcome acted or dismissed. The latest event per finding and day counts. | feedback_events.occurred_at | PR authors | category, severity (from the event) |
dismissed_rate | dismissed / (acted + dismissed), same scope as above | feedback_events.occurred_at | PR authors | category, severity |
comments_per_pr | Posted comments created that day / distinct pull requests with a completed or silent review run that day | posted_comments.created_at, review_runs.finished_at | PR authors | – |
silent_pr_rate | Review runs with decision silent / review runs with status completed or silent | review_runs.finished_at | PR authors | – |
findings | Findings with status published | findings.created_at | PR authors | category, severity |
time_to_first_review | First finished_at of a completed or silent review run minus pull_requests.opened_at (fallback created_at); mean, median and 90th percentile | first review | PR authors | – |
time_to_merge | merged_at minus opened_at (fallback created_at) of merged pull requests; mean, median and 90th percentile | pull_requests.merged_at | PR authors | – |
triage_label_acceptance | label_kept / (label_kept + label_removed); latest event per triage run, label and day | feedback_events.occurred_at | Issue authors | – |
duplicate_hits | Triage runs with at least one entry in result.duplicates | triage_runs.created_at | Issue authors | – |
assignment_kept_rate | Assignments with outcome kept / assignments with an outcome; only suggested or applied rows, never shadow | assignments.outcome_at | Authors of the assigned PRs and issues | – |
fix_pr_merge_rate | Published fix runs whose pull request is merged / published fix runs | fix_runs.finished_at | Issue authors | – |
llm_tokens | Input plus output tokens; split by token kind gives input, output, cached and cache-write tokens | llm_calls.created_at | – (cost) | feature, model, tier, token kind |
llm_cost_eur | Sum of cost_eur | llm_calls.created_at | – (cost) | feature, model, tier |
cache_hit_rate | Cached tokens / input tokens | llm_calls.created_at | – (cost) | feature, model |
Percentiles are interpolated from duration buckets (DURATION_BUCKETS_SECONDS); values above the largest bucket are reported as that bound. A split a metric does not support is reported as dimension_not_supported. Model calls without a repository count towards the tenant scope only.
Rollups and retention ​
The worker task analytics_rollup runs hourly. Per tenant it recomputes the last 3 days (ANALYTICS_ROLLUP_LOOKBACK_DAYS) and, on the first run, the last 90 days (ANALYTICS_BACKFILL_DAYS) into analytics_daily (additive numerators and denominators per repository, day, metric and dimension value; no person columns). Re-runs replace the same days. Rows older than the tenant's data retention are deleted. The screens show when the data was last updated.
Pull requests store opened_at, closed_at and merged_at from GitHub from this release on; older pull requests fall back to created_at and are not backfilled.
Budget alerts ​
The worker task budget_alerts runs every 15 minutes and compares model spend (llm_calls.cost_eur) in the current budget period with the tenant budget and each repository budget (model policy Budget). The period starts at floor(epochDay / periodDays) * periodDays (UTC). Each threshold (50, 80 and 100 % by default, chosen in Analytics → Settings) raises one alert per scope and period. An alert appears as a banner on the analytics and overview pages, is written to the audit log (budget.alert, actor system) and logged as a warning. Acknowledging it is audited. Each new alert is also sent to the notification channels that subscribe to budget alerts (Slack, Microsoft Teams, e-mail or a signed webhook; see notifications.md).
CSV export ​
GET …/analytics?…&format=csv (and /costs) returns metric,dimension,dimension_value,period,value,numerator,denominator. Hidden points are left out. Cells starting with =, +, -, @, tab or carriage return are escaped against formula injection. Responses are sent with cache-control: no-store. Personal metrics cannot be exported.