Introduce duo_code_review_flow_priority feature flag and update Modes::Dap#active? to route Duo Enterprise users through DAP when consent is given

Summary

Introduce the duo_code_review_flow_priority feature flag and update Ai::DuoCodeReview::Modes::Dap#active? so that Duo Enterprise users are routed through DAP when the new feature flag is enabled and their group has explicitly consented (via the group_consents table introduced in #602688 (closed)). The existing duo_code_review_dap_internal_users override is preserved as a fast-path that bypasses the consent requirement.

This is part of epic &22247.

Depends on: #602688 (closed) (group_consents table and Groups::Consent model must exist first).


Why

Today, Modes::Dap#active? short-circuits for any user with a Duo Enterprise add-on:

# Current behaviour
return ::Feature.enabled?(:duo_code_review_dap_internal_users, user) if user_has_duo_enterprise_add_on?

This means Code Review Flow being enabled for the namespace is completely ignored for Duo Enterprise users — they always fall through to Modes::Classic. The fix inverts the priority: if the new feature flag is on and the group has consented, DAP wins regardless of Duo Enterprise seat assignment.

The duo_code_review_dap_internal_users flag is kept as an explicit override for GitLab-internal users, allowing us to test the full flow before rolling out to customers.


What

1. Feature flag

Add ee/config/feature_flags/ops/duo_code_review_flow_priority.yml:

---
name: duo_code_review_flow_priority
description: >
  When enabled, the Code Review Flow toggle and group consent become the
  authoritative routing signal for Duo Code Review, taking priority over
  Duo Enterprise seat assignment. Requires explicit group consent recorded
  in group_consents (feature_name: code_review_flow_dap_routing).
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/<this_issue>
introduced_by_url: # filled in by MR
rollout_issue_url: # to be created
milestone: '19.2'
group: group::ai coding
type: ops
default_enabled: false

2. Updated Modes::Dap#active? logic

The current Duo Enterprise branch is a single early return:

# Before
return ::Feature.enabled?(:duo_code_review_dap_internal_users, user) if user_has_duo_enterprise_add_on?

It becomes a structured block with three explicit paths:

# After
if user_has_duo_enterprise_add_on?
  # Fast-path override: internal GitLab users bypass the consent requirement.
  # Preserves existing behaviour — no change for users covered by this flag.
  return true if ::Feature.enabled?(:duo_code_review_dap_internal_users, user)

  # New path: route through DAP if the feature flag is on AND the group has
  # explicitly consented to DAP routing (recorded in group_consents).
  if ::Feature.enabled?(:duo_code_review_flow_priority)
    return container.root_ancestor.consented_to?(:code_review_flow_dap_routing) &&
      container.duo_code_review_dap_available? &&
      duo_agent_platform_configured?
  end

  # Default: Duo Enterprise without the new flag → not active, falls through to Classic.
  return false
end

The non-Duo-Enterprise branch (Duo Pro/Core) is unchanged.

Decision table for Duo Enterprise users after this change:

duo_code_review_dap_internal_users duo_code_review_flow_priority Group consented? Result
enabled (for user) any any DAP (existing override, unchanged)
disabled enabled yes DAP (new path)
disabled enabled no Classic
disabled disabled any Classic (existing behaviour, unchanged)

How

  1. Add ee/config/feature_flags/ops/duo_code_review_flow_priority.yml.
  2. Update active? in ee/app/models/ai/duo_code_review/modes/dap.rb as described above.
  3. Update ee/spec/models/ai/duo_code_review/modes/dap_spec.rb to cover all new branches inside the when user has duo_enterprise add-on context:
    • duo_code_review_dap_internal_users enabled → active (existing spec, verify it still passes).
    • duo_code_review_dap_internal_users disabled + duo_code_review_flow_priority enabled + group consented → active.
    • duo_code_review_dap_internal_users disabled + duo_code_review_flow_priority enabled + group not consented → not active.
    • duo_code_review_dap_internal_users disabled + duo_code_review_flow_priority disabled → not active (existing behaviour).
  4. Verify all existing non-Duo-Enterprise specs still pass without modification.

Acceptance criteria

  • duo_code_review_flow_priority feature flag exists, default_enabled: false, type ops.
  • When duo_code_review_dap_internal_users is enabled for a Duo Enterprise user, active? returns true regardless of consent or the new flag (existing override preserved).
  • When duo_code_review_flow_priority is enabled and the group has a Groups::Consent record for :code_review_flow_dap_routing, active? returns true for Duo Enterprise users (subject to duo_code_review_dap_available? and duo_agent_platform_configured?).
  • When duo_code_review_flow_priority is enabled but the group has not consented, active? returns false for Duo Enterprise users (falls through to Classic).
  • When duo_code_review_flow_priority is disabled, Duo Enterprise behaviour is identical to today (no regression).
  • Non-Duo-Enterprise (Duo Pro/Core) routing is completely unchanged.
  • All new branches are covered by unit tests in dap_spec.rb.

Out of scope

  • Writing the consent record from the UI (Issues 4 & 5).
  • Any frontend changes.
  • Changes to Modes::Classic or ModeResolver.