Source code for ralph.agents.idle_watchdog.corroboration_snapshot

"""Corroboration snapshot for idle watchdog."""

from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass
from typing import TYPE_CHECKING

from ._evidence_tier import (
    ChannelEvidenceSummary,
    ChannelName,
)

if TYPE_CHECKING:
    from ralph.process._alive_by import AliveBy


# Backward-compatible re-exports. The canonical definitions now live in
# ``_evidence_tier.py`` so the tier model is centralised; this module keeps
# the same public surface for existing consumers.
__all__ = [
    "ChannelEvidenceSummary",
    "ChannelName",
    "CorroborationSnapshot",
    "WaitingCorroborator",
]


[docs] @dataclass(frozen=True) class CorroborationSnapshot: """Advisory snapshot of corroborating signals for WAITING_ON_CHILD diagnosis. All fields are Optional so callers without a given source can leave them None. Corroborators are advisory only; they NEVER affect WatchdogVerdict. The hard stop is determined solely by max_waiting_on_child_seconds and max_session_seconds. Per-channel activity evidence fields (mcp_tool_call_count, subagent_progress_count, last_mcp_tool_call_at, last_subagent_progress_at, last_workspace_event_at) carry the evidence the watchdog needs to defer a NO_OUTPUT_DEADLINE verdict while work is happening on a non-stdout channel. They default to None so existing construction sites remain valid; a fully-populated snapshot is the canonical "rich" evidence surface that IdleWatchdog.last_evidence_summary() reduces for the verdict hook. """ workspace_event_count: int | None = None oldest_child_seconds: float | None = None scoped_child_active: bool | None = None scoped_child_count: int | None = None terminal_child_events_total: int | None = None last_activity_was_meaningful: bool | None = None alive_by: AliveBy | None = None mcp_tool_call_count: int | None = None subagent_progress_count: int | None = None last_mcp_tool_call_at: float | None = None last_subagent_progress_at: float | None = None last_workspace_event_at: float | None = None current_run_idle_elapsed_seconds: float | None = None
WaitingCorroborator = Callable[[], CorroborationSnapshot]