Krikri::NeedleLookup
Ansible's controller-side relative-src lookup (ActionBase ._find_needle -> DataLoader.path_dwim_relative_stack): the ordered
candidate list a missing file's "Could not find or access" error
reports, and the same list resolution searches. Behavior matched to
ansible-core's dataloader.py, live-verified against ansible-playbook
for template:/copy:/script:/unarchive: with a missing relative src
(playbook-dir task and in-role task):
for each path in the task's search stack:
<path>/<dirname>/<src> (the dirname-skip condition in real
compares bytes against str and never
fires, so this entry is ALWAYS added)
<path>/<src>
then, always, the loader basedir as last resort:
<basedir>/<dirname>/<src>
<basedir>/<src>
The message shape comes from AnsibleFileNotFound.init: with a non-empty path list the " on the Ansible Controller." tail lands after the LAST searched path (no list at all for an absolute src, whose lookup never populates one). Since 2.21 the "If you are using a module ... remote_src option" sentence is the exception's help text (_default_help_text), not part of the raised message - the message ends at " on the Ansible Controller." in the fatal result, and for script:/template: the console caused-by segment carries no hint at all (live-verified vs 2.21.6).
Class methods
Matches DataLoader._is_role's shape: a directory that looks like a role because it (or its parent) holds a main.yml/meta/tasks entry.
The task's search stack: Ansible's Task.get_search_path() - the
role dependency chain, current role first, then the directory of
the file the task lives in (deduplicated against the role paths).
The basedir is NOT part of this - path_dwim_relative_stack appends
it unconditionally in #candidates.