Aggregation Components ====================== The Task Tracker delegates the interpretation and aggregation of subtask updates to dedicated support components. In particular, aggregation logic is implemented by: - :class:`~ska_csp_lmc_common.commands.aggregation.SubtaskResult` - :class:`~ska_csp_lmc_common.commands.aggregation.TaskAggregationPolicy` These components encapsulate domain-specific rules and keep the Task Tracker focused on orchestration and state tracking rather than decision logic. SubtaskResult model ------------------- Each subtask update received by the Task Tracker is stored as a :class:`~ska_csp_lmc_common.commands.aggregation.SubtaskResult`. A ``SubtaskResult`` captures both execution state and contextual metadata. At a minimum it stores: - ``name``: subtask identifier (used as the stable key in the tracker); - ``status``: the latest :class:`~ska_control_model.TaskStatus`; - ``result_code`` and ``message``: parsed from the ``result`` field. In addition, it may carry contextual information used for observability and aggregation: ``device_name`` The originating device, when available (e.g., the subsystem device that produced the update). ``devices`` The list of devices involved in the subtask (deduplicated, stable order). ``failed_devices`` The list of devices that failed for that subtask. When not available, the policy may fall back to ``device_name`` for failure reporting. ``operation`` / ``obs_mode`` Optional context fields used to support context-aware aggregation rules. Result parsing and message formatting ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The ``result`` field accepted by ``SubtaskResult`` supports multiple formats, for compatibility with different producers: - a tuple/list ``(ResultCode, message)`` - a JSON-encoded pair (string representation of a two-element list/tuple) - a ``ResultCode`` value or integer coercible to ``ResultCode`` - legacy strings (e.g. ``"Completed"``), which are mapped to an OK result When a ``device_name`` is available, the message is automatically prefixed with the device name to provide clear origin attribution. AggregationOutcome ------------------ The aggregation policy produces an ``AggregationOutcome`` containing: - a final task :class:`~ska_control_model.TaskStatus` - a final :class:`~ska_control_model.ResultCode` - an aggregated human-readable message - an optional aggregated ``health_state`` (e.g. ``FAILED`` / ``DEGRADED``) The Task Tracker uses this outcome to update its own public fields and to build the completion payload. Result code normalization (future improvement) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The aggregation policy may normalize subtask result codes when producing the final aggregated outcome. At present, result-code normalization is applied only to specific CBF-related rejection scenarios. In these cases, ``ResultCode.UNKNOWN`` is replaced with a meaningful result code consistent with the aggregated task status. In the future, the policy may be extended to apply similar normalization rules to other subsystems and terminal task states (e.g. ``FAILED`` or ``ABORTED``), in order to: - avoid ambiguous aggregated outcomes; - improve consistency across subsystems; - provide clearer semantics to consumers. Consumers should therefore treat the exact result-code normalization rules as subject to evolution. This normalization improves interoperability and avoids ambiguous outcomes for consumers.