atlas-iac/services/hermes/scripts/cli_lane_capabilities.py
2026-08-17 08:16:35 -03:00

131 lines
4.6 KiB
Python

#!/usr/bin/env python3
"""Detect and publish the Kanban API boundary required by CLI lanes."""
from __future__ import annotations
import inspect
import sys
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Any, Callable
from cli_lane_config import STATE_ROOT, utc_now
from cli_lane_files import atomic_json, load_json
_CAPABILITIES: KanbanCapabilities | None = None
_CAPABILITY_SOURCE: tuple[int, int] | None = None
@dataclass(frozen=True)
class KanbanCapabilities:
"""Safety-relevant keyword support exposed by the image's Kanban DB."""
exact_run_completion: bool
ended_run_replay: bool
exact_run_reclaim: bool
@property
def ready(self) -> bool:
"""Return whether dispatch and every recovery transition are safe."""
return (
self.exact_run_completion
and self.ended_run_replay
and self.exact_run_reclaim
)
@property
def deferred_features(self) -> tuple[str, ...]:
"""List fixed, bounded capability names absent from the image API."""
missing = []
if not self.exact_run_completion:
missing.append("exact-run-completion")
if not self.ended_run_replay:
missing.append("ended-run-replay")
if not self.exact_run_reclaim:
missing.append("exact-run-reclaim")
return tuple(missing)
def _explicit_keyword(function: Callable[..., Any], keyword: str) -> bool:
"""Require an explicit keyword parameter rather than trusting ``**kwargs``."""
try:
parameter = inspect.signature(function).parameters.get(keyword)
except (TypeError, ValueError):
return False
return parameter is not None and parameter.kind in {
inspect.Parameter.POSITIONAL_OR_KEYWORD,
inspect.Parameter.KEYWORD_ONLY,
}
def detect_kanban_capabilities(kanban_db: Any) -> KanbanCapabilities:
"""Inspect the loaded image API without invoking a mutating DB operation."""
complete_task = getattr(kanban_db, "complete_task", None)
reclaim_task = getattr(kanban_db, "reclaim_task", None)
return KanbanCapabilities(
exact_run_completion=callable(complete_task)
and _explicit_keyword(complete_task, "expected_run_id"),
ended_run_replay=callable(complete_task)
and _explicit_keyword(complete_task, "replay_ended_run_id"),
exact_run_reclaim=callable(reclaim_task)
and _explicit_keyword(reclaim_task, "expected_run_id"),
)
def _source_identity(kanban_db: Any) -> tuple[int, int]:
"""Bind cached capability evidence to the two inspected callables."""
return (
id(getattr(kanban_db, "complete_task", None)),
id(getattr(kanban_db, "reclaim_task", None)),
)
def _health_document(capabilities: KanbanCapabilities) -> dict[str, Any]:
"""Return a bounded operator-readable compatibility health document."""
return {
"component": "cli-lane-runner",
"state": "ready" if capabilities.ready else "deferred",
"ready": capabilities.ready,
"active_run_completion_safe": capabilities.exact_run_completion,
"deferred_features": list(capabilities.deferred_features),
"capabilities": asdict(capabilities),
"observed_at": utc_now(),
}
def initialize_kanban_capabilities(
kanban_db: Any,
*,
health_path: Path | None = None,
) -> KanbanCapabilities:
"""Detect startup compatibility and durably expose ready/deferred health."""
global _CAPABILITIES, _CAPABILITY_SOURCE
capabilities = detect_kanban_capabilities(kanban_db)
_CAPABILITIES = capabilities
_CAPABILITY_SOURCE = _source_identity(kanban_db)
destination = health_path or STATE_ROOT / "runtime-health.json"
destination.parent.mkdir(parents=True, exist_ok=True)
atomic_json(destination, _health_document(capabilities), 0o600)
if not capabilities.ready:
print(
"CLI lane safety compatibility deferred; missing image APIs: "
+ ", ".join(capabilities.deferred_features),
file=sys.stderr,
flush=True,
)
return capabilities
def kanban_capabilities(kanban_db: Any) -> KanbanCapabilities:
"""Return startup evidence, redetecting only when the loaded API changes."""
if _CAPABILITIES is None or _source_identity(kanban_db) != _CAPABILITY_SOURCE:
return initialize_kanban_capabilities(kanban_db)
return _CAPABILITIES
def runtime_health(path: Path | None = None) -> dict[str, Any]:
"""Read the bounded health document for probes and operator diagnostics."""
document = load_json(path or STATE_ROOT / "runtime-health.json")
return document if isinstance(document, dict) else {}