Add WorkItemGenerateWorkplan mutation for async workplan flow

What does this MR do and why?

Adds an async, non-interactive way to generate a work item's workplan: the WorkItemGenerateWorkplan GraphQL mutation and its backing Ai::DuoWorkflows::GenerateWorkplanService, which start a Duo Agent Platform flow (workplan/v1) instead of requiring a live Duo Chat session.

This is the first backend building block for the async work item refinement loop described in #605157 (closed): today a workplan can only be drafted interactively via Duo Chat, which ties one user to one plan at a time. Moving generation into a CI-backed flow lets a user kick off several refinements in parallel and get notified only when input is needed, instead of babysitting one chat session per work item.

Both the mutation and service are self-contained behind the duo_workplan_async_flow feature flag (default off, introduced in !248543 (merged)).

How it works

  • workItemGenerateWorkplan(id: WorkItemID!) authorizes :update_work_item on the work item, then delegates to GenerateWorkplanService, returning the started workflow (or errors).
  • The service validates, in order:
    • the work item belongs to a project (the flow runs in CI, so group-level work items aren't supported) → PROJECT_REQUIRED_ERROR
    • duo_workplan_async_flow is enabled for the project → FEATURE_DISABLED_ERROR
    • the workplan/v1 foundational flow definition exists (Ai::Catalog::FoundationalFlow) → FLOW_UNAVAILABLE_ERROR
    • no non-terminal workflow is already running for this work item + flow definition → WORKFLOW_ALREADY_RUNNING_ERROR
  • The goal is built by Ai::Catalog::GoalTemplates::Workplan, a one-line template that only names the target work item URL. Plan format, ambiguity handling, and the question-escalation protocol intentionally live solely in the workplan/v1 system prompt in gitlab-ai-gateway, not here — a single source of truth for agent behavior instead of a second copy to keep in sync.
  • Starts the flow via the existing Ai::DuoWorkflows::CreateAndStartWorkflowService.
  • WORKFLOW_DEFINITION_REFERENCE = 'workplan/v1' is the string the widget status field, the discussion-resolved worker, and the frontend "Generate workplan" button will all key off of in follow-up MRs — none of those are part of this change.

Also in this MR

  • A follow-up commit fixes 3 spec failures surfaced by isolating this change from the full branch:
    • Added the with_non_terminal_status scope to Ai::DuoWorkflows::Workflow (present in the full branch, missing here since this is a split-out substrate MR).
    • Updated the foundational-flow count assertion in seed_foundational_flows_service_spec.rb (11 → 12) for the new workplan/v1 entry.
    • Raised the query-limit assertion in groups/update_service_spec.rb (140 → 150); the new foundational flow pushed CascadeSyncFoundationalFlowsWorker's query count to 144 (tracked in #598945).

Out of scope (this iteration)

Per the parent work item's constraints — tracked as follow-ups, not this MR:

  • Surfacing workflow progress on the work item (widget status field).
  • Reacting to flow completion (discussion-resolved worker).
  • The frontend entry point (button).
  • Work items with children (no hierarchies) and live collaborative chat (comments only) remain unsupported.

References

Edited by Stefanos Xanthopoulos

Merge request reports

Loading
Loading