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 context is nil (type instantiated outside a GraphQL request), context&.query&.mutation? is falsy and tracking proceeds — the safe default.

References

Screenshots or screen recordings

Not applicable — backend-only change to internal event tracking, no UI change.

How to set up and validate locally

  1. Enable the feature flag: Feature.enable(:workplan) in a rails console.
  2. Create a work item with an agent plan (or call workItemEnableAiPlanning to create one).
  3. Run the updateWorkItemAgentPlan mutation for the work item and confirm the response includes content/contentHtml.
  4. Confirm no work_item_agent_plan_read internal event is recorded for the save (e.g. by checking Gitlab::InternalEvents usage counters for the work_item_agent_plan_read event), 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.

Merge request reports

Loading
Loading