Skip to content

Read changed hosts from the play recap, not the last task - #80

Merged
shipmill-romamo[bot] merged 1 commit into
mainfrom
fix/76-changed-from-play-stats
Oct 11, 2026
Merged

shipmill-romamo[bot] merged 1 commit into
mainfrom
fix/76-changed-from-play-stats

Conversation

@shipmill-romamo

Copy link
Copy Markdown
Contributor

Summary

_preview sorted hosts into changed/unchanged from the files Ansible's tree callback leaves, but that callback rewrites each host's file after every task, so only the last task's result survived. A run whose recap said ok=5 changed=2 was recorded changed: [], and a verify run with changed=1 was recorded verified. The check preview, the execution and the verify run all went through it.

  • New callback plugin shipped in the wheel, cloudfall/callback_plugins/cloudfall_host_stats.py: on v2_playbook_on_stats it writes one JSON file per host with its ok, changed, failed and unreachable counts from stats.summarize(host)
  • run_command enables it (ANSIBLE_CALLBACKS_ENABLED=cloudfall_host_stats, CLOUDFALL_HOST_STATS_DIR=<per-run dir>) and sets ANSIBLE_CALLBACK_PLUGINS to the plugin's directory followed by the callback path Ansible would otherwise use (the operator's env, else the team's ansible.cfg with relative entries resolved against it, else Ansible's default), read in process with ConfigManager in cloudfall.ansible_api. Ansible has no append form for this variable, so this is how the team's callback_plugins is kept
  • _preview marks a host changed when its changed count is above 0, and fails fast (decision_host_stats_invalid) on a file without an integer count. The record schema is unchanged
  • The tree callback is dropped: nothing else in sdk/, engine/, demo/, evaluations/ or docs/ reads it, and ansible-core deprecates it (removal in 2.23). The per-run directory moves from decisions/tree/<id> to decisions/host-stats/<id>
  • Replay (recording._write_host_stats) writes the same files: a recorded changed host as ok=1 changed=1, an unchanged one as ok=1 changed=0. Recordings under examples/ and demo/ are untouched
  • PlaybookInvocation.tree is renamed host_stats

Records already carrying wrong values are out of scope (see #77).

Test plan

  • sdk/tests/test_host_stats.py
    • End to end against real ansible-playbook on localhost (the suite already does this): a two-task playbook whose first task changes and whose last reports ok is recorded changed in the check preview, the execution and the verify step, and the decision ends failed, not verified
    • The callback, loaded through Ansible's callback_loader, on an AggregateStats built in the test
    • run_command keeps the team's callback_plugins after the plugin directory and no longer sets the tree variables
    • A malformed host stats file is refused; replay round-trips changed/unchanged
  • The fake runner in test_decision.py now writes recap counts
  • uv sync, uv run ruff check ., uv run mypy, uv run pytest (523 passed), uv run cloudfall config validate --project config/examples all pass; nothing under engine/ansible changed. uv build --wheel lists cloudfall/callback_plugins/cloudfall_host_stats.py

Fixes #76

🤖 Generated with Claude Code

The tree callback rewrites each host's file after every task, so
_preview saw only the last task's result: a run whose recap said
changed=2 was recorded changed: [], and a verify run that changed a
host was recorded verified. The check preview, the execution and the
verify run now read each host's ok/changed/failed/unreachable counts
from a callback the SDK ships (cloudfall_host_stats), written from the
play stats on v2_playbook_on_stats. The tree callback, read by nothing
else and deprecated in ansible-core, is no longer enabled. The plugin
directory is put ahead of the callback path the team's ansible.cfg (or
the operator's environment) already names, since setting
ANSIBLE_CALLBACK_PLUGINS replaces it. Replay writes the same files.

Fixes #76

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shipmill-romamo
shipmill-romamo Bot merged commit c3f9121 into main Oct 11, 2026
1 check passed
@shipmill-romamo
shipmill-romamo Bot deleted the fix/76-changed-from-play-stats branch October 11, 2026 18:37
@shipmill-romamo shipmill-romamo Bot added this to the 0.7.0 milestone Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Decision records take a host's changed flag from its last task only, so verify can pass a run that changed the host

0 participants