Track namespace-level agent sessions with their namespace
What does this MR do and why?
This MR passes the workflow's namespace to track_internal_event in track_workflow_event, so the six agent_platform_session_* events for a namespace-level Duo Agent Platform session carry that namespace. Until now they carried none. Events already recorded keep no namespace. CleanStuckWorkflowsService already makes the same call for its cleanup event.
Why the namespace is missing
Every workflow has exactly one of project_id and namespace_id (check_73884a5839 on duo_workflows_workflows), and track_workflow_event passed only the user and the project. With no project, neither Gitlab::InternalEvents nor Gitlab::Tracking::AiTracking can resolve a namespace. The Snowplow context has no namespace_id. The PostgreSQL ai_usage_events row has a NULL namespace_id, and the ClickHouse row has no namespace in namespace_path or traversal_path. Both Ai::UsageEventsFinder backends, which serve Resolvers::Analytics::AiUsage::UsageEventsResolver, filter a group's events on those columns (namespace_id and traversal_path), so these sessions never match.
Event path for a namespace-level session
sequenceDiagram
participant S as Ai::DuoWorkflows services
participant T as track_workflow_event
participant IE as Gitlab::InternalEvents
participant AT as Gitlab::Tracking::AiTracking
participant UE as Ai::UsageEvent
S->>T: agent_platform_session_* event
T->>IE: track_internal_event(user:, project:, namespace:)
Note over T,IE: Before: project is nil, no namespace passed<br/>After: namespace is workflow.namespace
IE->>IE: Snowplow and Redis: namespace, else project.namespace
IE->>AT: track_event with the caller's arguments
AT->>UE: project namespace first, else namespace
Note over IE,UE: Before: no namespace in Snowplow or ai_usage_events<br/>After: the session's namespace in bothProject-level sessions are unchanged
A project-level workflow has no namespace_id, so it passes namespace: nil. Gitlab::InternalEvents still derives the namespace from the project, and Gitlab::Tracking::AiTracking still takes the project's project_namespace first, so these events record the same namespace as before.
The cleanup spec
@pgumeson recorded this gap in !249723 (merged) and asserted it in clean_stuck_workflows_service_spec.rb so it would stay visible. That example now expects the namespace, and a new spec for the concern covers a project-level and a namespace-level workflow.
References
- Follow-up to !249723 (merged)
- Related to https://gitlab.com/gitlab-org/gitlab/-/work_items/594005
- Related to https://gitlab.com/gitlab-org/gitlab/-/work_items/627196
- !256455 (merged) edits the same cleanup spec example. The two changes apply together without conflict.
How to set up and validate locally
-
Run the new concern spec, the cleanup spec and the three other caller specs:
bundle exec rspec ee/spec/services/ai/duo_workflows/concerns/workflow_event_tracking_spec.rb \ ee/spec/services/ai/duo_workflows/clean_stuck_workflows_service_spec.rb \ ee/spec/services/ai/duo_workflows/create_workflow_service_spec.rb \ ee/spec/services/ai/duo_workflows/update_workflow_status_service_spec.rb \ ee/spec/services/ai/duo_workflows/create_and_start_workflow_service_spec.rbRan locally with this change: 327 examples, 0 failures, 1 pending (already pending on master). RuboCop reports no offenses on the three changed files.
-
Revert the one-line change in
workflow_event_tracking.rband rerun the first two specs. Ran locally: 37 examples, 8 failures. The failures are the concern spec's seven namespace-level examples and the cleanup spec's namespace-leveldroppedexample, and the project-level example still passes. -
On a group's page, start a chat with Add new chat on the GitLab Duo sidebar, then query the group's
aiUsageDatain GraphQL as a group Owner. Tested on a self-managed GitLab 19.4.1 instance with a stub model behind a self-hosted AI gateway, with sessions started from the web UI on a group and on one of its projects. 19.4.1's copy of the concern lacks the agent configuration properties on master, so only thenamespace: workflow.namespaceline was ported to it.- Group-level sessions: the
ai_usage_eventsrows for created, started, resumed (a second prompt), stopped (Cancel session) and dropped (a prompt sent while the model was unreachable) carry the group'snamespace_id, and the Owner'saiUsageDataread returns them. Without the change,namespace_idis NULL and the read omits them. - Project-level rows still carry the project's
project_namespace, as they did without the change for created and started. - A group-level session cannot reach
finishedon 19.4.1, so that event was not tested by hand at group level. The concern spec covers all six events for a namespace-level workflow.
- Group-level sessions: the
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
This MR was prepared with assistance from Claude Code.