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::Executor overrides the base tracking hook to fall back to resource.resource_parent (the epic's group) when context.project is nil — the same scoping its authorize and ai_request already use.
  • Llm::GenerateDescriptionService passes both project: and namespace: (the Gitlab::DuoChatResourceHelper helpers); AiTracking.related_namespace gives 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:

  1. 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.
  2. Confirm one Ai::UsageEvent row 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.rb with both project-shaped and group-shaped contexts for both events (both are group-capable).
  • doc/api/graphql/reference/_index.md and public/-/graphql/introspection_result.json are regenerated at the branch base.

Related to https://gitlab.com/gitlab-org/gitlab/-/issues/567159

Edited by Andrew Dunn

Merge request reports

Loading