Repository navigation
fix(ansible): two update-path regressions — python_interpreter_binary scope, code_source_dir default (#16750) - #16752
Merged
Conversation
The browser role's pip task referenced python_interpreter_binary right after a plain include_role of python_interpreter -- a dynamic include keeps a role's defaults private unless public: true is set, so the variable was undefined on a real update-all run on 2026-09-14. The same shape existed in agent_config, backend_services, npu-worker and tts-worker; all five now mark the include public: true rather than duplicating the default. _shared/tasks/sync_deletions.yml templated bare code_source_dir, which the frontend role never sets, silently skipping its deletion pass. Computed once as a local fallback (_sd_code_source_dir, the same override-first default its callers already use) and used at all three sites. Adds guard tests for both regression shapes, with fixtures reproducing the pre-fix browser and sync_deletions shapes to prove the detectors would have caught them.
Contributor
|
Warning Review limit reachedNext included review available in 18 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (9)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Contributor
✅ SSOT Configuration Compliance: Passing🎉 No new hardcoded values of either class — Known backlog in |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Thinking Path
Both regressions surfaced on a real
update-allrun on 2026-09-14; CI neverexecutes Ansible, so neither was caught there. Traced each to the exact
scoping rule it violates, then applied the fix mechanically everywhere the
same shape recurred, rather than patching only the one site that happened to
fail first.
(a)
python_interpreter_binaryis a role default(
roles/python_interpreter/defaults/main.yml). Ansible's rule:include_role(dynamic) keeps an included role's defaults private to that role's own task
execution unless
public: trueis set — even for later tasks in the samefile.
import_role(static) and ameta/main.ymldependency don't have thisproblem; their defaults merge into play/role scope unconditionally. Swept
every file referencing the variable (
git grep -n python_interpreter_binary)and classified each by which of the three shapes puts
python_interpreterinscope.
(b)
_shared/tasks/sync_deletions.ymltemplated barecode_source_dir,which not every caller sets (the frontend role never does). Its siblings
(
sync_deletions_source_dir, and_shared/tasks/record_slm_deployed_commit.yml)already use an override-first, SSOT-derived default for the same concept —
applied the identical shape here instead of inventing a new one.
What Changed
(a) —
roles/python_interpreterinclude sites (11 files referencepython_interpreter_binary;roles/python_interpreter/defaults/main.ymldefines it and
roles/python_interpreter/tasks/main.ymlis the role's owntask file, so neither needs an include):
roles/agent_config/tasks/main.ymlinclude_role(dynamic)public: true— also coverspython_env.yml,python_deps.yml,openvino.yml,playwright.yml, allinclude_tasks'd after it in the same playroles/agent_config/tasks/python_env.ymlmain.yml's now-public includeroles/agent_config/tasks/python_deps.ymlroles/agent_config/tasks/openvino.ymlroles/agent_config/tasks/playwright.ymlroles/backend_services/tasks/main.ymlinclude_role(dynamic)public: trueroles/browser/tasks/main.ymlinclude_role(dynamic)public: true(the reported regression)roles/npu-worker/tasks/main.ymlinclude_role(dynamic)public: trueroles/tts-worker/tasks/main.ymlinclude_role(dynamic)public: trueroles/python_interpreter/tasks/main.ymlNo default was duplicated or hardcoded anywhere —
public: truekeepsroles/python_interpreter/defaults/main.ymlthe single source.(b) —
roles/_shared/tasks/sync_deletions.yml: added oneset_factasthe first task inside the existing
block:(not a sibling before it, sothe file keeps the single top-level block/rescue task the #16310 wiring
tests assert on):
and switched all three sites (
git -c safe.directory=/-C, the diff-plan--repo-root, the bootstrap-plan--repo-root) from barecode_source_dirto
_sd_code_source_dir. The delegated-to-localhost tasks still templateagainst the iterated host's vars —
set_facthere runs undelegated, so thefact lands in that host's hostvars before any
delegate_to: localhosttaskreads it.
Guard tests (
repo_tests/):ansible_python_interpreter_binary_scope_16750_test.py— sweeps everyAnsible file for
{{ python_interpreter_binary }}and fails if the owningrole/play has no meta dependency,
import_role, orinclude_role(public: true)forpython_interpreter. Includes fixturesreproducing the pre-fix browser shape (asserted broken) and the fixed shape
(asserted in scope), plus meta-dependency and
import_rolefixtures.ansible_shared_tasks_code_source_dir_default_16750_test.py— sweepsroles/_shared/tasks/*.ymlfor any{{ ... code_source_dir ... }}expression with no
default(in the same expression. Includes fixturesreproducing the pre-fix
sync_deletions.ymlshape (asserted broken) and thefixed shape (asserted defaulted).
repo_tests/glob_declared_reads_15900_test.pyupdated: both new guardsdeclare
"*.yml"viarglob, added to the existing recorded set.Verification
ansible-playbook --syntax-checkon every playbook that reaches the fivefixed roles or
sync_deletions.yml:playbooks/update-all-nodes.yml,playbooks/deploy-full.yml,playbooks/deploy-native-services.yml,playbooks/provision_host.yml,playbooks/recover_host.yml(with-e target_host=dummy),deploy.yml— all pass.python3 -m pytest repo_tests/ansible_python_interpreter_binary_scope_16750_test.py repo_tests/ansible_shared_tasks_code_source_dir_default_16750_test.py repo_tests/glob_declared_reads_15900_test.py— 41 passed.pytest repo_tests/ -k "ansible or sync_deletions or python_interpreter"— 223 passed, 1 pre-existing unrelated failure(
scan_helpers_vacuity_test.py::test_the_ansible_reference_checker_refuses_when_nothing_resolved,reproduced identically on
origin/mainbefore this change — a localModuleNotFoundError: tools.lintsubprocess/PYTHONPATH issue, not caused bythis diff).
repo_tests/sync_deletions_ansible_wiring_16310_test.pyandsync_deletions_target_pinning_and_shell_safety_16310_test.py(both assertthe file's single top-level block/rescue task, marker-write ordering,
rescue behavior, injection safety) — all still pass unmodified.
update-allrun succeeding against these roles) ispending — never run Ansible from this session.
Closes #16750
Single-issue rationale
#16750 fixes two regressions that today's merges put into the live update path: the browser venv task (#16721,
python_interpreter_binaryout of scope) and the sync-deletions step (#16351, barecode_source_dir). Both failed on a real update-all run. No other open issue shares this scope, and holding it for a batch would leave update-all broken on the owner's install.Model Used
Sonnet 5