compose_networks, container_networks and compose_external_networks each rebuilt
the same Ansible-side context before calling their renderer: resolve the
variables, settle the deployment mode, load applications, build the service
registry, and close over the config and database lookups. Around forty lines,
three times, each with its own copy of _resolve_var. A change to how the
registry or the closures are obtained could reach one lookup and miss another.
build_context() returns that context once. honour_mode_force carries the only
real difference between the callers: compose_external_networks never consulted
compose_mode_force, and still does not.
The lookups keep only what is theirs - term validation, their own arguments,
their renderer call - and drop from 94/90/87 lines to 59/54/53.
No assertion changed in the tests; only the mock targets moved with the seam,
from the plugin modules to utils.networks.lookup_context. Twelve legacy comments
in those test files lost their grandfathering when the files entered the lint's
diff scope: two became docstrings naming the call contract, the rest were
narration and are gone.
Behaviour-preserving: the same 13 lookup tests pass before and after.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>