Quick action preview inconsistently omits commands due to transient MR state

Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.

  • Label this issue

Summary

The quick action preview in the MR comment box inconsistently omits commands when multiple quick actions are used together (e.g. /approve, /run_pipeline, /merge). Sometimes all three appear in the preview, sometimes only a subset (e.g. 2 out of 3) is shown. Which command is omitted varies — it is not always the same one.

Steps to reproduce

  1. Open a merge request
  2. In the comment box, type:
    /approve
    /run_pipeline
    /merge
  3. Observe the preview — it may show all three commands, or only a subset
  4. Repeat on different MRs — the behavior is inconsistent

Observed behavior

  • In some MRs, all three commands appear in the preview
  • In others, only 2 of 3 appear (e.g. /run_pipeline and /merge show but /approve does not)
  • The subset shown can differ across MRs in the same project and across projects

See the original report in #210538 (comment 3060722435) for screenshots and specific examples.

Expected behavior

The preview should consistently show all applicable quick actions.

Root cause analysis

The preview is generated via the preview_markdown endpoint, which calls QuickActions::InterpretService#explain. For each command, CommandDefinition#explain (lib/gitlab/quick_actions/command_definition.rb:45-46) calls available?, which evaluates the command's condition block against the MR's current state. If available? returns false, the command is silently omitted from the preview.

Each command's condition (lib/gitlab/quick_actions/merge_request_actions.rb) performs stateful checks:

  • /approve (line 260): calls eligible_for_approval_by? — in EE this loads approval rules, associated users/groups, and checks the approvals table via ApprovalState
  • /run_pipeline (line 516): calls CreatePipelineService#allowed? — checks pipeline existence and user permissions
  • /merge (line 47): calls merge_orchestration_service.can_merge? — cascades into mergeable? → check_mergeability, which acquires an exclusive lease and can trigger a Gitaly merge-to-ref operation

All of these conditions are sensitive to the MR's transient state (e.g. merge_status being unchecked after a push, exclusive lease contention, approval rules loading). When any condition returns false due to timing, the corresponding command silently disappears from the preview.

Relevant files

  • lib/gitlab/quick_actions/command_definition.rb — available? / explain gating
  • lib/gitlab/quick_actions/merge_request_actions.rb — condition blocks for /merge, /approve, /run_pipeline
  • app/services/preview_markdown_service.rb — preview service
  • app/services/quick_actions/interpret_service.rb — explain method
  • app/services/merge_requests/merge_orchestration_service.rb — can_merge?
  • app/services/merge_requests/mergeability_check_service.rb — exclusive lease logic
Edited Feb 18, 2026 by 🤖 GitLab Bot 🤖
Assignee Loading
Time tracking Loading