ansible.builtin.command and ansible.builtin.shell cannot know whether the command they ran altered anything, so they report changed on every run. A playbook built from them is not idempotent, --check mode is meaningless for those tasks, and any handler they notify fires on every run.
There are three ways to fix a given task. creates: /path skips the task when the path exists, which suits installers and unpackers. removes: /path is the inverse. changed_when takes an expression evaluated against the result, so changed_when: "'already exists' not in result.stdout" reports accurately for a command that is safe to rerun.
failed_when is the companion for commands whose exit codes do not mean what Ansible assumes. Prefer a real module where one exists, because modules implement check mode and idempotency properly. Ansible prints a warning when command is used for something a module covers, for example command: rm -rf /tmp/x suggesting the file module; that warning can be disabled with warn: false in older versions but the underlying advice stands.