4.2 KiB
AIM per-target final execution outcomes
AIM 3.3.0rc8 / service API 1.0. Capability: target_outcome_summary_v1.
Core's overall execution result remains authoritative and unchanged. An Ansible run
with one unreachable target still returns, for example, status: failed, execution
stage and the native nonzero exit code. The additive target summary answers a
different question: what final Ansible outcome did each requested target have?
Result fields
Every RunResult now contains:
{
"target_summary": {
"schema": "target_outcome_summary_v1",
"requested": 25,
"successful": 24,
"failed": 0,
"unreachable": 1,
"not_started": 0,
"indeterminate": 0,
"complete": true,
"accounted": 25
},
"targets": [
{
"host": "host01.example",
"outcome": "successful",
"counts": {
"ok": 38,
"changed": 0,
"failures": 0,
"unreachable": 0,
"skipped": 22,
"rescued": 0,
"ignored": 0
}
}
]
}
The targets list is in the reviewed request order. accounted always equals
requested. Capability discovery advertises the schema, state vocabulary and that
the data is available in both summary and detail progress modes.
Outcome semantics
Core derives these states from Ansible's final per-host stats callback, not from aggregate task counters or a client's interpretation of progress events:
unreachable: final host stats contain one or more unreachable results.failed: no unreachable count, but final host stats contain unresolved failures.successful: final host stats were emitted for the requested host and contain neither unresolved failures nor unreachable results. Changed/skipped/rescued/ ignored task counts do not by themselves make the host unsuccessful.not_started: a complete final stats set was received, but the requested host had no final host stats; or execution ended before remote work could start.indeterminate: remote execution may have started but Core did not receive a complete final stats set (for example cancellation, process loss or invalid event stream). Core deliberately does not infer success from earlier task events.
If both failure and unreachable counters exist for one host, unreachable takes
precedence because the target did not remain reachable through the execution.
Per-target counts are task counters for diagnostics; the outcome field is the
Core-owned final classification.
This describes Ansible execution truth, not arbitrary application-level semantics. A playbook that intentionally ignores a module error or reports a domain-specific problem without failing remains subject to the playbook's own Ansible semantics.
Overall status remains separate
A mixed run can therefore be represented as:
Core RunResult: failed / execution / exit 4
Target facts: 24 successful, 1 unreachable
An interface may choose a presentation label such as Partially succeeded, but
that label is not a Core status and must not replace or hide the authoritative
Core result.
Pre-execution ServiceError responses remain errors rather than fake partial
success. When execute returns a RunResult before launch, targets are accounted
as not_started and remote_work_may_have_started remains false.
Transport and safety
The native callback sends only target indexes and numeric recap counts through the private event bridge. Public host names come from the already reviewed request, not arbitrary callback payloads. No raw module output, variable data, credentials, exception text or task result dictionaries are added.
Consumers should use this result instead of reconstructing final target outcomes
from play_task_host_v1. Detailed events remain useful for live presentation; the
final target summary is the authoritative end-state accounting.
Report validation is a separate layer
A native exit 0 and successful target stats do not prove a required operation report was published. 3.3.0rc8 can fail the Core result at result_validation while preserving those native target facts and exit_code 0. See OPERATION_RESULTS.md. Do not convert a missing report into fake target success, nor rewrite native counts to express a report-contract error.