Expose user field on SessionArtifactType GraphQL type
What does this MR do and why?
Exposes a nullable user field on Types::Ai::DuoWorkflows::SessionArtifactType so the Agent Artifacts table can display which user initiated a session.
The Ai::DuoWorkflows::SessionArtifact model already has a belongs_to :user association with user_id required and populated from the workflow's user_id on sync, but this user was not exposed via GraphQL.
Changes:
SessionArtifactType: adds a nullableuserfield of typeUserType. The resolver handles both object shapes:- ActiveRecord path (PostgreSQL finder): reads
object.user, preloaded to avoid N+1. - Hash path (ClickHouse finder): batch-loads
Userbyuser_idviaBatchModelLoader.
- ActiveRecord path (PostgreSQL finder): reads
SessionArtifactmodel: addsscope :with_userusingpreload(:user)(consistent with the existingwith_projectscope, and safe across the in-operator optimization subquery rewrite).PostgresqlFinder: chains.with_userafter.with_projectto preload users for the AR path.ClickHouseFinder: addsuser_idto the projectedCOLUMNSso it is available in the Hash objects returned to the type.- GraphQL reference docs: manually updated
doc/api/graphql/reference/_index.mdwith the newuserfield entry (thegitlab:graphql:compile_docsRake task requires a database connection not available in this environment; CI will regenerate the full schema). - Specs: type spec covers both AR and Hash paths; request spec adds a
userfield assertion and an N+1 guard.
References
Related to #606639
Screenshots or screen recordings
How to set up and validate locally
- In a Rails console, find or create a
Ai::DuoWorkflows::SessionArtifactrecord. - Query the GraphQL API:
{ group(fullPath: "<group>") { duoWorkflowSessionArtifacts(first: 5) { nodes { id user { username } } } } } - Verify the
userfield returns the correct username.
Database review
New query introduced by scope :with_user, -> { preload(:user) } on Ai::DuoWorkflows::SessionArtifact, used to eager-load the new user GraphQL field on the PostgreSQL path. This uses preload (not includes/joins), so it always runs as a separate query rather than being merged into the session artifacts CTE — a plain primary-key lookup independent of the artifacts query's complexity.
Raw SQL:
SELECT "users".* FROM "users" WHERE "users"."id" IN (1614863, <second_user_id>)Query plan: https://console.postgres.ai/gitlab/projects/gitlab-production-main/sessions/54079/commands/156478
An N+1 guard test (ee/spec/requests/api/graphql/ai/duo_workflows/session_artifacts_spec.rb) confirms this query runs once per page regardless of how many distinct users are referenced.
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.
