ACTIVITY-WP-0043: owner-return pickup adapter (STATE-WP-0094-T03 owner side)
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 1m28s

Disabled reviewed definition, pinned profile/grant, server-side unique
submission adapter with receipts, and opt-in activation plan. No schedule,
deployment or dispatch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 671493@bnt-lap001
Assistant-Session: 60d7b11f-78f9-4731-9367-918511b2762d
This commit is contained in:
tegwick 2026-10-04 12:42:43 +02:00
parent ab10835a0c
commit 5a9012453c
5 changed files with 541 additions and 0 deletions

View file

@ -0,0 +1,159 @@
"""Tests for the owner-return pickup adapter (ACTIVITY-WP-0043)."""
from __future__ import annotations
import uuid
from pathlib import Path
from unittest.mock import AsyncMock, MagicMock
import pytest
from activity_core import owner_return_pickup as orp
from activity_core.definition_parser import parse_file
from activity_core.sync_activity_definitions import _definition_uuid
REPO, TASK = "ops-warden", "WARDEN-WP-0041-T03"
MSG = "11111111-2222-3333-4444-555555555555"
DEF_PATH = Path(__file__).parent.parent / "activity-definitions" / "owner-return-pickup.md"
def _candidate(**over):
c = {
"target_repo": REPO, "task_record_id": TASK, "message_id": MSG,
"activity_definition_id": orp.ACTIVITY_DEFINITION_ID,
"triggering_event_id": orp.owner_return_event_id(REPO, TASK, MSG),
"disposition": "reviewable", "stop_reason": None, "ops_run_id": None,
}
c.update(over)
return c
@pytest.fixture
def enabled(monkeypatch):
monkeypatch.setenv(orp.ENABLE_ENV, "true")
monkeypatch.delenv("OPS_RUN_QUEUE_ENABLED", raising=False)
def _session(insert_id, existing=None):
session = MagicMock()
ins = MagicMock(); ins.scalar_one_or_none.return_value = insert_id
sel = MagicMock(); sel.first.return_value = existing
session.execute = AsyncMock(side_effect=[ins, sel])
return session
def test_identity_matches_sync_derivation():
assert orp.ACTIVITY_DEFINITION_ID == str(_definition_uuid("owner-return-pickup"))
def test_definition_source_is_disabled_and_inert():
d = parse_file(DEF_PATH)
assert d.id == "owner-return-pickup"
assert d.enabled is False
text = DEF_PATH.read_text()
assert "enabled: false" in text and 'condition: "False"' in text
assert orp.HARNESS_PROFILE_REF in text
def test_event_id_matches_state_hub_planner_encoding():
# Reference value: json.dumps([repo, task, msg], separators=(",", ":")) sha256.
import hashlib, json
raw = json.dumps([REPO, TASK, MSG], separators=(",", ":")).encode()
assert orp.owner_return_event_id(REPO, TASK, MSG) == (
"owner-return:" + hashlib.sha256(raw).hexdigest()
)
def test_grant_is_local_only():
assert orp.REPOSITORY_GRANT["publish"] is False
assert orp.REPOSITORY_GRANT["allowed_paths"] == ["workplans"]
@pytest.mark.parametrize("over", [
{"triggering_event_id": "owner-return:" + "0" * 64},
{"message_id": "not-a-uuid"},
{"activity_definition_id": str(uuid.uuid4())},
{"target_repo": "Bad Repo"},
{"task_record_id": ""},
])
def test_binding_rejects_mismatch(over):
with pytest.raises(orp.OwnerReturnError):
orp.OwnerReturnBinding.from_candidate(_candidate(**over))
def test_spec_key_is_stable():
b = orp.OwnerReturnBinding.from_candidate(_candidate())
spec = b.task_spec()
assert spec.source_id == f"{REPO}/{TASK}"
assert spec.triggering_event_id == b.triggering_event_id
assert spec.activity_definition_id == orp.ACTIVITY_DEFINITION_ID
async def test_refuses_when_not_enabled(monkeypatch):
monkeypatch.delenv(orp.ENABLE_ENV, raising=False)
session = _session(None)
with pytest.raises(orp.OwnerReturnError):
await orp.submit_owner_returns(session, [_candidate()], collection_complete=True)
session.execute.assert_not_called()
async def test_refuses_when_queue_disabled(enabled, monkeypatch):
monkeypatch.setenv("OPS_RUN_QUEUE_ENABLED", "false")
with pytest.raises(orp.OwnerReturnError):
await orp.submit_owner_returns(_session(None), [_candidate()], collection_complete=True)
async def test_refuses_incomplete_collection(enabled):
session = _session(None)
with pytest.raises(orp.OwnerReturnError, match="paginated"):
await orp.submit_owner_returns(session, [_candidate()], collection_complete=False)
session.execute.assert_not_called()
async def test_invalid_candidate_aborts_before_any_write(enabled):
session = _session(None)
bad = _candidate(triggering_event_id="owner-return:" + "f" * 64)
with pytest.raises(orp.OwnerReturnError):
await orp.submit_owner_returns(session, [_candidate(), bad], collection_complete=True)
session.execute.assert_not_called()
async def test_inserted_receipt(enabled):
rid = uuid.uuid4()
session = _session(rid)
[r] = await orp.submit_owner_returns(session, [_candidate()], collection_complete=True)
assert r["status"] == "inserted" and r["ops_run_id"] == str(rid)
assert r["idempotency_key"] == (
f"{orp.ACTIVITY_DEFINITION_ID}:{REPO}/{TASK}:{orp.owner_return_event_id(REPO, TASK, MSG)}"
)
stmt = session.execute.await_args_list[0].args[0]
from sqlalchemy.dialects import postgresql
sql = str(stmt.compile(dialect=postgresql.dialect())).upper()
assert "ON CONFLICT (IDEMPOTENCY_KEY) DO NOTHING" in sql
assert session.execute.await_count == 1
async def test_duplicate_reports_existing_row(enabled):
existing_id = uuid.uuid4()
session = _session(None, existing=(existing_id, "succeeded"))
[r] = await orp.submit_owner_returns(session, [_candidate()], collection_complete=True)
assert r["status"] == "duplicate"
assert r["ops_run_id"] == str(existing_id) and r["state"] == "succeeded"
async def test_duplicate_without_row_raises(enabled):
with pytest.raises(orp.OwnerReturnError):
await orp.submit_owner_returns(_session(None, existing=None), [_candidate()],
collection_complete=True)
@pytest.mark.parametrize("over", [
{"disposition": "stopped", "stop_reason": "needs_human"},
{"disposition": "pending", "ops_run_id": str(uuid.uuid4())},
{"disposition": "completed"},
])
async def test_non_reviewable_is_skipped_without_write(enabled, over):
session = _session(None)
[r] = await orp.submit_owner_returns(session, [_candidate(**over)], collection_complete=True)
assert r["status"] == "skipped"
session.execute.assert_not_called()