fix(mcp): the overview drops an Ansible failure a later run put right (#5842)
CI / lint (push) Successful in 2s
CI / unit (push) Successful in 1m29s
CI / integration (push) Successful in 1m34s
CI / publish (push) Successful in 1m29s

get_overview listed every failed or interrupted run of the last 24 hours,
so a dry run that failed, was fixed and re-run green kept warning for a
day. A failure now drops out once a later success of the same playbook,
source and hosts is at least as real: an applied success clears either
kind of failure, a dry-run success only a dry-run failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-15 13:58:24 -04:00
co-authored by Claude Opus 5.5
parent eee8469a17
commit 70eb253190
2 changed files with 44 additions and 0 deletions
+19
View File
@@ -195,6 +195,25 @@ def test_run_findings_quote_the_failures():
assert f["kind"] == "ansible_run_failed" and "apt lock held" in f["summary"]
def _run(status, ago, *, check=False, scope="steward:target:util", playbook="upkeep/x.yml"):
return NS(id=f"{status}-{ago}", source_name="steward-local", playbook_path=playbook,
inventory_scope=scope, status=status, started_at=NOW - timedelta(minutes=ago),
params={"check": check})
def test_a_failed_run_put_right_since_is_not_a_finding():
F, S = AnsibleRunStatus.failed, AnsibleRunStatus.success
dry_fail, real_fail = _run(F, 60, check=True), _run(F, 50)
# A dry run fixed and re-run dry: the dry failure is cleared, the real one is not.
assert overview.still_failing([dry_fail, real_fail], [_run(S, 55, check=True)]) == [real_fail]
# A dry success after a real failure doesn't clear it; a real success does.
assert overview.still_failing([real_fail], [_run(S, 40, check=True)]) == [real_fail]
assert overview.still_failing([real_fail], [_run(S, 40)]) == []
# A success elsewhere, or before the failure, clears nothing.
assert overview.still_failing([real_fail], [_run(S, 40, scope="steward:target:other"),
_run(S, 40, playbook="upkeep/y.yml"), _run(S, 70)]) == [real_fail]
def test_rank_puts_critical_first_then_oldest():
fs = [overview.finding("warning", "k", "w-old", "", since=NOW - timedelta(days=1)),
overview.finding("critical", "k", "c-new", "", since=NOW - timedelta(minutes=1)),