Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"node_id": "omnibase_infra.nodes.node_runner_fleet_health_compute",
"receipt_schema": "handflip_proof.v1",
"canonical_handler_module": "omnibase_infra.nodes.node_runner_fleet_health_compute.handlers.handler_runner_fleet_health_evaluate",
"legacy_handler_module": "omnibase_infra.nodes.node_runner_fleet_health_compute.handlers.handler_runner_fleet_health_evaluate",
"base_ref": "426b92b2e8d414eb7be21b43d780181417cbf7df",
"preserved_symbols": [
"_classify_runner",
"_annotate_indeterminate",
"_recommend_for_assessment"
],
"parity": {
"status": "pass",
"test_ids": [
"tests/unit/nodes/node_runner_fleet_maintain/test_runner_fleet_health_dispatch_entrypoint_omn14830.py::test_handler_handle_is_single_request_adaptable",
"tests/unit/nodes/node_runner_fleet_maintain/test_runner_fleet_health_dispatch_entrypoint_omn14830.py::test_real_dispatch_callback_returns_verdict[healthy]",
"tests/unit/nodes/node_runner_fleet_maintain/test_runner_fleet_health_dispatch_entrypoint_omn14830.py::test_real_dispatch_callback_returns_verdict[saturated]",
"tests/unit/nodes/node_runner_fleet_maintain/test_runner_fleet_health_dispatch_entrypoint_omn14830.py::test_real_dispatch_callback_returns_verdict[crashloop_and_zombie]",
"tests/unit/nodes/node_runner_fleet_maintain/test_runner_fleet_health_dispatch_entrypoint_omn14830.py::test_real_dispatch_callback_returns_verdict[wedged]",
"tests/unit/nodes/node_runner_fleet_maintain/test_runner_fleet_health_dispatch_entrypoint_omn14830.py::test_multipositional_handle_breaks_dispatch_is_the_red",
"tests/unit/nodes/node_runner_fleet_maintain/test_runner_fleet_health_dispatch_entrypoint_omn14830.py::test_dispatched_verdict_classifies_saturated_incident"
],
"selected_input_hashes": [
"sha256:417282720dab4036ac8ebd1f8366cafa152ec9b2018e2330eb13153e7ccde972",
"sha256:df52a84157445fab2d0bc621c6469e04c6717911aaed04afced80bcf320b0f61",
"sha256:9448a3ffc5de0e9ea71bf310f7bfdf160d4fa9b2747359608c624f9babd72903",
"sha256:9283b33ea2d37421bb39d2b80e545c21f36f738418d7dcbca9d639666416781c",
"sha256:253c682105a45d8380c31de8eeb0981e3090416f566197daa95e85f453c85ff8",
"sha256:9abadaa2b1d881f14b2c561e53e96f3453f4a4447ddccede6043b1c450143c64",
"sha256:83864536efebbf49db80ec91ed4e335de940c8650b8b3012561d84b1a3a1454f",
"sha256:578f43255f6fd6db46693d3748374c1739515d3fb949df10789aa337b817a2a7",
"sha256:fda1e6b3995c79834845b7a97a547bda0afcf69671c118e61cce44bce8766dec"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"branch_coverage_pct": 80.67,
"candidate_count": 17,
"coverage_target": 80.0,
"handler_module": "omnibase_infra.nodes.node_runner_fleet_health_compute.handlers.handler_runner_fleet_health_evaluate",
"handler_module_sha256": "sha256:521297d503f9efa4c5879269eb8051a5128403f115105b7f61807d5d04f31d0d",
"meets_target": true,
"node_id": "omnibase_infra.nodes.node_runner_fleet_health_compute",
"receipt_schema": "adequacy_receipt.v1",
"recorded_at": "2026-07-20T05:34:57.682418+00:00",
"recorder_schema": "adequacy_receipt.v1",
"selected_count": 9,
"selected_input_hashes": [
"sha256:417282720dab4036ac8ebd1f8366cafa152ec9b2018e2330eb13153e7ccde972",
"sha256:df52a84157445fab2d0bc621c6469e04c6717911aaed04afced80bcf320b0f61",
"sha256:9448a3ffc5de0e9ea71bf310f7bfdf160d4fa9b2747359608c624f9babd72903",
"sha256:9283b33ea2d37421bb39d2b80e545c21f36f738418d7dcbca9d639666416781c",
"sha256:253c682105a45d8380c31de8eeb0981e3090416f566197daa95e85f453c85ff8",
"sha256:9abadaa2b1d881f14b2c561e53e96f3453f4a4447ddccede6043b1c450143c64",
"sha256:83864536efebbf49db80ec91ed4e335de940c8650b8b3012561d84b1a3a1454f",
"sha256:578f43255f6fd6db46693d3748374c1739515d3fb949df10789aa337b817a2a7",
"sha256:fda1e6b3995c79834845b7a97a547bda0afcf69671c118e61cce44bce8766dec"
],
"uncovered_waiver": null,
"volatile_mask": []
}
1 change: 0 additions & 1 deletion scripts/ci/canonical_handler_shape_baseline.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@
"omnibase_infra.nodes.node_rsd_orchestrator",
"omnibase_infra.nodes.node_rsd_score_compute",
"omnibase_infra.nodes.node_rsd_state_reducer",
"omnibase_infra.nodes.node_runner_fleet_health_compute",
"omnibase_infra.nodes.node_runner_fleet_maintain_orchestrator",
"omnibase_infra.nodes.node_runner_health_snapshot_effect",
"omnibase_infra.nodes.node_runtime_error_triage_effect",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ name: "node_runner_fleet_health_compute"
contract_version:
major: 1
minor: 0
patch: 0
node_version: "1.0.0"
patch: 1
node_version: "1.0.1"
node_type: "COMPUTE_GENERIC"
description: >
Pure, deterministic classifier of a runner-fleet snapshot into a typed health verdict: per-runner state, fleet aggregates, and recorded (never executed) recommended actions.
Pure, deterministic classifier of a runner-fleet snapshot into a typed health verdict: per-runner state, fleet aggregates, and recorded (never executed) recommended actions. Uses the canonical def-B typed ModelRunnerFleetHealthEvaluateCommand handler entrypoint.

input_model:
name: "ModelRunnerFleetHealthEvaluateCommand"
Expand Down Expand Up @@ -79,12 +79,15 @@ published_events:
"retention.ms": "604800000"
"cleanup.policy": "delete"
metadata:
description: "Runner-fleet health classifier (OMN-13942 Increment 1 -- read-only detection core)"
description: "Runner-fleet health classifier (OMN-13942 Increment 1 -- read-only detection core) with canonical def-B typed handler entrypoint."
author: "OmniNode Team"
license: "MIT"
created: "2026-07-04"
updated: "2026-07-20"
ticket: "OMN-14830"
tags:
- compute
- def-b
- health
- runner
- fleet-maintain
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
import logging
import os
from datetime import UTC, datetime
from uuid import UUID

from omnibase_infra.enums import EnumHandlerType, EnumHandlerTypeCategory
from omnibase_infra.nodes.node_runner_fleet_health_compute.models.enum_recommended_action_type import (
Expand All @@ -48,6 +47,9 @@
from omnibase_infra.nodes.node_runner_fleet_health_compute.models.model_recommended_action import (
ModelRecommendedAction,
)
from omnibase_infra.nodes.node_runner_fleet_health_compute.models.model_runner_fleet_health_evaluate_command import (
ModelRunnerFleetHealthEvaluateCommand,
)
from omnibase_infra.nodes.node_runner_fleet_health_compute.models.model_runner_fleet_health_verdict import (
ModelRunnerFleetHealthVerdict,
)
Expand All @@ -57,9 +59,6 @@
from omnibase_infra.nodes.node_runner_health_snapshot_effect.models.model_runner_fleet_runner_fact import (
ModelRunnerFleetRunnerFact,
)
from omnibase_infra.nodes.node_runner_health_snapshot_effect.models.model_runner_fleet_snapshot import (
ModelRunnerFleetSnapshot,
)

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -215,18 +214,27 @@ def handler_category(self) -> EnumHandlerTypeCategory:
return EnumHandlerTypeCategory.COMPUTE

async def handle(
self, correlation_id: UUID, snapshot: ModelRunnerFleetSnapshot
self, request: ModelRunnerFleetHealthEvaluateCommand
) -> ModelRunnerFleetHealthVerdict:
"""Classify ``snapshot`` into a ``ModelRunnerFleetHealthVerdict``.
"""Classify the command's snapshot into a ``ModelRunnerFleetHealthVerdict``.

Canonical ONEX definition B (OMN-14355): a single typed-payload
``request`` the shared runtime adapter binds via the contract
``input_model``. The correlation id and facts-only snapshot are unpacked
from the command; classification is byte-identical to the pre-flip
two-argument entrypoint (OMN-14781 signature adaptation -- no behavior
change).

Args:
correlation_id: Workflow correlation ID.
snapshot: Facts-only snapshot gathered by the EFFECT node.
request: Command carrying the workflow correlation id and the
facts-only snapshot gathered upstream by the EFFECT node.

Returns:
ModelRunnerFleetHealthVerdict with per-runner states, fleet
aggregates, and recorded (never executed) recommended actions.
"""
correlation_id = request.correlation_id
snapshot = request.snapshot
online_count = sum(1 for r in snapshot.runners if r.github_status == "online")
offline_count = sum(1 for r in snapshot.runners if r.github_status != "online")
busy_count = sum(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
from omnibase_infra.nodes.node_runner_fleet_health_compute.models.enum_runner_fleet_health_state import (
EnumRunnerFleetHealthState,
)
from omnibase_infra.nodes.node_runner_fleet_health_compute.models.model_runner_fleet_health_evaluate_command import (
ModelRunnerFleetHealthEvaluateCommand,
)
from omnibase_infra.nodes.node_runner_health_snapshot_effect.models.model_runner_fleet_runner_fact import (
ModelRunnerFleetRunnerFact,
)
Expand Down Expand Up @@ -68,7 +71,9 @@ async def test_all_online_and_idle_is_healthy(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert all(
a.state == EnumRunnerFleetHealthState.HEALTHY for a in verdict.assessments
Expand All @@ -95,7 +100,9 @@ async def test_zero_idle_all_busy_is_saturated(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert all(
a.state == EnumRunnerFleetHealthState.SATURATED for a in verdict.assessments
Expand Down Expand Up @@ -123,7 +130,9 @@ async def test_crash_loop_and_zombie_present(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
states = {a.name: a.state for a in verdict.assessments}
assert states["omninode-runner-1"] == EnumRunnerFleetHealthState.CRASH_LOOPING
Expand All @@ -146,7 +155,9 @@ async def test_offline_runner_is_offline_idle(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert verdict.assessments[0].state == EnumRunnerFleetHealthState.OFFLINE_IDLE
assert verdict.offline_count == 1
Expand All @@ -171,7 +182,9 @@ async def test_zombie_run_candidate_recommends_cancel_run(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
cancel_actions = [
a
Expand All @@ -195,7 +208,9 @@ async def test_buildx_unavailable_classifies_runners(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert verdict.buildx_unavailable is True
assert (
Expand All @@ -215,7 +230,9 @@ async def test_codeload_throttle_signals_classify_runners(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert verdict.codeload_throttle_signal_count == 3
assert (
Expand All @@ -234,7 +251,9 @@ async def test_buildx_takes_precedence_over_codeload(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert (
verdict.assessments[0].state
Expand All @@ -258,7 +277,9 @@ async def test_fleet_wide_wedge_with_zero_busy(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert all(
a.state == EnumRunnerFleetHealthState.WEDGED for a in verdict.assessments
Expand All @@ -274,7 +295,9 @@ async def test_no_wedge_when_queue_age_below_threshold(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert verdict.assessments[0].state == EnumRunnerFleetHealthState.HEALTHY

Expand All @@ -293,10 +316,14 @@ async def test_identical_input_produces_identical_classification(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict_a = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
verdict_b = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert [a.state for a in verdict_a.assessments] == [
a.state for a in verdict_b.assessments
Expand All @@ -322,7 +349,9 @@ async def test_default_sources_ok_are_determinate(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert verdict.github_source_ok is True
assert verdict.docker_source_ok is True
Expand All @@ -348,7 +377,9 @@ async def test_docker_source_failure_marks_every_assessment_indeterminate(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert verdict.docker_source_ok is False
assert all(a.is_determinate is False for a in verdict.assessments)
Expand All @@ -365,7 +396,9 @@ async def test_github_source_failure_marks_every_assessment_indeterminate(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert verdict.github_source_ok is False
assert all(a.is_determinate is False for a in verdict.assessments)
Expand All @@ -384,7 +417,9 @@ async def test_typed_rearm_signals_survive_as_fields_not_just_free_text(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
by_name = {a.name: a for a in verdict.assessments}
assert by_name["omninode-runner-1"].docker_restart_count == 9
Expand All @@ -402,7 +437,9 @@ async def test_buildx_none_is_not_collapsed_into_confirmed_available(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert verdict.buildx_unavailable is False
assert verdict.buildx_determinate is False
Expand All @@ -416,7 +453,9 @@ async def test_buildx_confirmed_available_is_determinate(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert verdict.buildx_unavailable is False
assert verdict.buildx_determinate is True
Expand All @@ -431,7 +470,9 @@ async def test_buildx_confirmed_unavailable_is_determinate(self):
)
handler = HandlerRunnerFleetHealthEvaluate()
verdict = await handler.handle(
correlation_id=snapshot.correlation_id, snapshot=snapshot
ModelRunnerFleetHealthEvaluateCommand(
correlation_id=snapshot.correlation_id, snapshot=snapshot
)
)
assert verdict.buildx_unavailable is True
assert verdict.buildx_determinate is True
Loading
Loading