Draft: Add AiTracking for two Duo description and summary features
What does this MR do and why?
Note
Stacked MR: this MR is built on and blocked by
!246385 (it uses the
SlashCommandTool usage-tracking hook introduced there). It targets that MR's
branch so the diff shows only this MR's changes; when !246385 merges it will
retarget to master and be rebased before review.
Adds Gitlab::Tracking::AiTracking coverage for two GitLab Duo features from
the audit in https://gitlab.com/gitlab-org/gitlab/-/issues/567159 that generate AI requests
but record no usage event:
| Feature | Event | ID | Firing site |
|---|---|---|---|
| Discussion Summary | summarize_comments |
43 | Tools::SummarizeComments::Executor via the SlashCommandTool usage hook |
| Issue Description Generation | generate_description |
44 | Llm::GenerateDescriptionService#perform |
Each event fires at the entry of the request path (not on :success), mirroring
Llm::ChatService#perform and the previously merged events in this series
(!240198 (merged),
!240662 (merged),
!241206 (merged)), so usage is recorded in
ai_usage_events (PostgreSQL and ClickHouse) and surfaces through the aiUserMetrics and
aiUsageData GraphQL fields for self-managed adoption reporting.
Group-level attribution
Discussion Summary runs on epics and Issue Description Generation runs on group-level work items; neither resource carries a project, so project-only attribution would silently drop those requests:
SummarizeComments::Executoroverrides the base tracking hook to fall back toresource.resource_parent(the epic's group) whencontext.projectis nil — the same scoping itsauthorizeandai_requestalready use.Llm::GenerateDescriptionServicepasses bothproject:andnamespace:(theGitlab::DuoChatResourceHelperhelpers);AiTracking.related_namespacegives the project precedence, so project-backed requests keep the exact attribution of sibling events while group-level work items attribute to their group.
Naming
Each event action matches its feature's canonical id (the aiAction method /
unit primitive and register_feature name) so usage traces to one name across
ai_usage_events, the GraphQL enum, and the generated <Feature>UserMetrics types.
The rationale is documented in each event YAML above action:.
Authorization
The auto-generated SummarizeCommentsUserMetrics and GenerateDescriptionUserMetrics
types are covered by the factory-level parent_authorizes skip from
!245901 (merged) — no
authorization_todo.txt entries are needed.
How to set up and validate locally
As a user on an Ultimate namespace with a Duo add-on seat:
-
Trigger each feature once:
- Discussion Summary: in Duo Chat on an issue or epic with comments, run
/summarize_comments. - Issue Description Generation: on a new issue, use the description field's AI "Generate description" action.
- Discussion Summary: in Duo Chat on an issue or epic with comments, run
-
Confirm one
Ai::UsageEventrow per request:Ai::UsageEvent.where(event: %w[summarize_comments generate_description])Epics and group-level work items carry the group's
namespace_id; project resources carry the project namespace.
Notes for reviewers
- Event IDs 43-44 are next-free following
!244736 (34/35/38) and
!246385 (39-42). Description
Composer is intentionally NOT instrumented here — !244736 already tracks it as
compose_merge_request_description(38) at the same firing site. - Negative paths covered: unauthorized (both), blank-notes early return
(
summarize_comments), non-member (generate_description). - Storage covered in
ai_tracking_spec.rbwith both project-shaped and group-shaped contexts for both events (both are group-capable). doc/api/graphql/reference/_index.mdandpublic/-/graphql/introspection_result.jsonare regenerated at the branch base.
Related to https://gitlab.com/gitlab-org/gitlab/-/issues/567159