Add activity-core ops_run client, approach selection (FI/Binky/mail/agent), claim-loop worker with lease heartbeat, CLI run --from-ops-run and claim-loop, install units, and docs demoting issue-core to legacy external tickets. T05 timer cutover remains operator after five clean cycles.
97 lines
3 KiB
Python
97 lines
3 KiB
Python
"""Claim loop process_one tests (REIN-A-0002-T03)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from rein_aharness.approaches import ApproachResult, APPROACH_FI_RESEARCH_BRIEF
|
|
from rein_aharness.claim_loop import process_one, poll_peek
|
|
from rein_aharness.ops_run_client import OpsRun, OpsRunConfig, ActivityCoreOpsClient
|
|
|
|
|
|
def _claimed_run() -> OpsRun:
|
|
return OpsRun(
|
|
id="run-1",
|
|
activity_definition_id="def",
|
|
idempotency_key="k",
|
|
target_repo="freedom-intelligence",
|
|
title="FI daily",
|
|
description="d",
|
|
labels=["automated", "research-brief"],
|
|
state="claimed",
|
|
claim_owner="worker-1",
|
|
attempt=1,
|
|
)
|
|
|
|
|
|
def test_process_one_empty() -> None:
|
|
client = MagicMock(spec=ActivityCoreOpsClient)
|
|
client.config = OpsRunConfig(worker_id="w", lease_seconds=90)
|
|
client.claim.return_value = []
|
|
r = process_one(client)
|
|
assert r.empty is True
|
|
assert r.claimed is False
|
|
|
|
|
|
def test_process_one_success_completes() -> None:
|
|
client = MagicMock(spec=ActivityCoreOpsClient)
|
|
client.config = OpsRunConfig(worker_id="w", lease_seconds=90)
|
|
client.claim.return_value = [_claimed_run()]
|
|
client.complete.return_value = OpsRun(
|
|
id="run-1",
|
|
activity_definition_id="def",
|
|
idempotency_key="k",
|
|
target_repo="freedom-intelligence",
|
|
title="FI daily",
|
|
description="",
|
|
state="succeeded",
|
|
labels=["automated", "research-brief"],
|
|
)
|
|
ar = ApproachResult(
|
|
ok=True,
|
|
approach=APPROACH_FI_RESEARCH_BRIEF,
|
|
result={"path": "briefs/x.md"},
|
|
reason="ok",
|
|
)
|
|
with patch("rein_aharness.claim_loop.execute_approach", return_value=ar):
|
|
r = process_one(client)
|
|
assert r.claimed is True
|
|
assert r.ok is True
|
|
assert r.approach == APPROACH_FI_RESEARCH_BRIEF
|
|
client.complete.assert_called_once()
|
|
client.fail.assert_not_called()
|
|
|
|
|
|
def test_process_one_failure_reopens() -> None:
|
|
client = MagicMock(spec=ActivityCoreOpsClient)
|
|
client.config = OpsRunConfig(worker_id="w", lease_seconds=90)
|
|
client.claim.return_value = [_claimed_run()]
|
|
client.fail.return_value = OpsRun(
|
|
id="run-1",
|
|
activity_definition_id="def",
|
|
idempotency_key="k",
|
|
target_repo="freedom-intelligence",
|
|
title="t",
|
|
description="",
|
|
state="open",
|
|
labels=["automated", "research-brief"],
|
|
)
|
|
ar = ApproachResult(
|
|
ok=False,
|
|
approach=APPROACH_FI_RESEARCH_BRIEF,
|
|
reason="llm timeout",
|
|
reopen=True,
|
|
)
|
|
with patch("rein_aharness.claim_loop.execute_approach", return_value=ar):
|
|
r = process_one(client)
|
|
assert r.ok is False
|
|
client.fail.assert_called_once()
|
|
assert client.fail.call_args.kwargs["reopen"] is True
|
|
|
|
|
|
def test_poll_peek() -> None:
|
|
client = MagicMock(spec=ActivityCoreOpsClient)
|
|
client.list_open.return_value = [_claimed_run()]
|
|
rows = poll_peek(client)
|
|
assert len(rows) == 1
|
|
assert rows[0]["approach"] == APPROACH_FI_RESEARCH_BRIEF
|