A task-level check_mode: false overrides --check

If one task sets check_mode itself, the command line flag no longer reaches it, and ansible-playbook --check -e apply=true mutates for real. Fold ansible_check_mode into the variable the task uses.

I wanted a role that never changes anything unless asked, with two ways to ask for a dry run: --check, and simply not passing -e apply=true. A task that installs a Helm chart looked like this:

- name: Install the controllers
  kubernetes.core.helm:
    name: flux2
    chart_ref: flux2
  check_mode: "{{ dry }}"

with dry derived from the apply switch. That works until you combine the two: --check -e apply=true. A task-level check_mode: wins over the global flag, so the task ran for real while the rest of the play was in check mode. Written as check_mode: false the damage is the same.

Fix

Make the variable know about the command line too:

vars:
  dry: "{{ ansible_check_mode or not (apply | bool) }}"

Now --check always forces the dry run, whatever else is set. I’d call it a rule for any role with its own switch: every task that sets check_mode: gets it from a variable that includes ansible_check_mode.

To test it, run --check -e apply=true against something you can afford to look at, and see whether anything changes.