A looped `include_tasks` or `include_role` leaves its item in scope for
everything the include reaches. Left at the default name, Ansible warns as
soon as any task inside loops as well, and the sharp case is quieter than the
warning: the included body reads `item` expecting the value the include was
called with, while an inner loop has already repointed the name. Nothing
fails, so the wrong value is written and the run reports success.
web-app-prometheus was carrying exactly that shape. It hands the item to an
included file through `vars:`, which Ansible templates lazily, so
`network_role_id` was one nested loop away from resolving to something else.
The rule complements the existing loop_var shadowing lint, which checks the
other direction and cannot see this one. It parses the task files rather than
scanning their lines: a line window around each include also catches the next
task's `loop:` and reports 55 findings where there are 22.
Fourteen of those are the plain dependency include and take
`dependency_role`, the name dsk-gnome already uses. The rest take a name for
what the item is. The gitlab and mastodon wait includes pass nothing through
`vars:` and their included file reads `item` four times, so each needed that
file renamed with it; naming only the parent would have left `item`
undefined.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add tests/lint/repository/test_task_file_numbering.py: numbered task
files use exactly two leading digits, a numbered *_core.yml must be
00_core.yml, per directory the numbers are unique/consecutive and start
at 01 (00 with a core file), numbered includes appear in ascending
order, and shared helpers live in tasks/utils/ instead of the numbered
chain.
Apply it across every role: rename NN_core.yml to 00_core.yml with a
consecutive down-shift of the siblings, move letter-suffix children into
a subdirectory named after their parent task, relocate helpers included
from more than one place into tasks/utils/, and update every reference
(include_tasks, path_absolute, .ansible-lint-ignore, requirement docs).
Legacy narration comments in the touched files are deleted; the upstream
xwiki.properties reference block opts out via nocheck. The unused
MAILU_IP6_PUBLIC var (only ever named in now-removed comments) is dropped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>