Don't track agent plan reads on mutation responses
What does this MR do and why?
Saving a workplan no longer counts as a "read" in the work_item_agent_plan_read internal event.
Both the updateWorkItemAgentPlan and workItemEnableAiPlanning mutations return WorkItemAgentPlanFragment, which selects content and contentHtml. Both field resolvers in Types::WorkItems::Widgets::AgentPlanType call track_agent_plan_read, so every save also fired the read event. The per-request SafeRequestStore guard deduplicates within a request but can't distinguish a mutation from a genuine read, inflating the metric and making it impossible to tell real reads from saves.
The fix adds a single guard in the instance-level track_agent_plan_read: return early when the current GraphQL operation is a mutation (context&.query&.mutation?). Both call sites (#content and the prepended ContentHtmlTracking#content_html_resolver) go through this method, so both are covered. The class method stays unchanged — a pure function of widget + user — so non-GraphQL callers and the existing class-method specs are unaffected.
Alternatives considered
- Guard in the class method: rejected — the class method is also called directly (specs, potential non-GraphQL contexts), so the mutation check belongs at the GraphQL-aware layer.
- Set a context flag in each mutation resolver: rejected — touches every mutation returning the fragment and needs updating for each new mutation; the
mutation?check is a single, future-proof guard. - If
contextis nil (type instantiated outside a GraphQL request),context&.query&.mutation?is falsy and tracking proceeds — the safe default.
References
- Resolves #628018 (closed)
- Follow-up from !253657 (merged) (see !253657 (comment 3799953133))
Screenshots or screen recordings
Not applicable — backend-only change to internal event tracking, no UI change.
How to set up and validate locally
- Enable the feature flag:
Feature.enable(:workplan)in a rails console. - Create a work item with an agent plan (or call
workItemEnableAiPlanningto create one). - Run the
updateWorkItemAgentPlanmutation for the work item and confirm the response includescontent/contentHtml. - Confirm no
work_item_agent_plan_readinternal event is recorded for the save (e.g. by checkingGitlab::InternalEventsusage counters for thework_item_agent_plan_readevent), while viewing the work item's plan in a normal query does record it.
Automated coverage added in ee/spec/graphql/types/work_items/widgets/agent_plan_type_spec.rb: resolving content under a mutation operation does not fire the event; under a query operation it does.
Note: specs were not executed in the authoring environment (no test database available); RuboCop and syntax checks pass, and the
GraphQL::Query#mutation?behavior was verified against the locked graphql-ruby 2.6.10.
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.