Add ai_planning_enabled field to work item agent plan widget

What does this MR do and why?

Implements the ai_planning_enabled field on work items, exposed and mutable via GraphQL. This is the backend part of #608882 (closed).

The Work Plan widget currently renders unconditionally on every work item. This MR adds a per-work-item ai_planning_enabled flag so the frontend can conditionally render the widget and its "Plan" CTA.

Changes

Database migration:

  • Adds ai_planning_enabled boolean NOT NULL DEFAULT false column to work_item_agent_plans table

Model (WorkItems::AgentPlan):

  • Adds validation preventing ai_planning_enabled from being set back to false once true (opt-in only)

GraphQL field (WorkItemWidgetAgentPlan):

  • Adds aiPlanningEnabled: Boolean! field
  • Inherits workplan feature flag gating from the existing widget

GraphQL mutation (WorkItemEnableAiPlanning):

  • Accepts workItemId (global ID)
  • Gated behind the workplan feature flag
  • Creates the AgentPlan if it does not exist yet, then sets ai_planning_enabled = true
  • Returns the updated work item
  • Enforces update_work_item authorization

Data sync:

  • Carries ai_planning_enabled over to the target plan when a work item is moved

Tests:

  • Model spec: validation that ai_planning_enabled cannot be unset
  • GraphQL type spec: aiPlanningEnabled field included
  • Mutation request spec: feature flag gating, authorization, create/update/idempotent paths, concurrent-creation retry, save failure

Naming

The field and mutation were originally called ai_enabled and WorkItemSetAiEnabled. Both were renamed after review, because they read as if AI were being turned on for the entire work item rather than for planning on the agent plan widget, and because "set" suggested a toggle when the flag is one-way. See the discussion.

References

Screenshots or screen recordings

N/A — backend-only change.

How to set up and validate locally

  1. Enable the feature flag for a group:
    Feature.enable(:workplan, Group.find_by_full_path('your-group'))
  2. Create a work item in that group.
  3. Run the mutation:
    mutation {
      workItemEnableAiPlanning(input: { id: "gid://gitlab/WorkItem/123" }) {
        workItem {
          widgets {
            ... on WorkItemWidgetAgentPlan {
              aiPlanningEnabled
            }
          }
        }
        errors
      }
    }
  4. Verify aiPlanningEnabled returns true.
  5. Verify the mutation is a no-op when called again (idempotent).

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.

Edited by Alexandru Croitor

Merge request reports

Loading
Loading