From 8f26263d4a42d8f1e64a0e94a65c369c5cec4f32 Mon Sep 17 00:00:00 2001 From: h Date: Mon, 19 Oct 2026 13:51:15 +0200 Subject: [PATCH] feat(conversations,jobs): a manual run of the rotation job rotates the master now --- src/beaver_gateway/conversations/rotation.py | 14 ++++++++++++-- src/beaver_gateway/jobs/job.py | 4 ++-- tests/test_rotation.py | 11 +++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/beaver_gateway/conversations/rotation.py b/src/beaver_gateway/conversations/rotation.py index 11a2b38..e3c947f 100644 --- a/src/beaver_gateway/conversations/rotation.py +++ b/src/beaver_gateway/conversations/rotation.py @@ -77,9 +77,19 @@ class Rotation: out.append((master, reason)) return out - async def tick(self, now: datetime | None = None) -> list[Conversation]: + async def tick( + self, now: datetime | None = None, *, force: str | None = None + ) -> list[Conversation]: + """Rotate the masters that are due; ``force`` rotates every open master.""" rotated: list[Conversation] = [] - for master, reason in await self.due(now): + if force: + due = [ + (m, force) + for m in await self._conversations.find(kind="master", status="open") + ] + else: + due = await self.due(now) + for master, reason in due: new = await self.rotate(master, reason) if new is not None: rotated.append(new) diff --git a/src/beaver_gateway/jobs/job.py b/src/beaver_gateway/jobs/job.py index e576023..0b77654 100644 --- a/src/beaver_gateway/jobs/job.py +++ b/src/beaver_gateway/jobs/job.py @@ -118,9 +118,9 @@ class JobRun: self.job, self.payload, delay=delay, trigger=self.trigger ) - async def rotate(self) -> list[Conversation]: + async def rotate(self, *, force: str | None = None) -> list[Conversation]: rotation = self.scheduler.rotation - return await rotation.tick() if rotation is not None else [] + return await rotation.tick(force=force) if rotation is not None else [] def background(self, coro: Coroutine[Any, Any, Any]) -> None: self.scheduler.background(coro) diff --git a/tests/test_rotation.py b/tests/test_rotation.py index f600daf..9b674ef 100644 --- a/tests/test_rotation.py +++ b/tests/test_rotation.py @@ -84,6 +84,17 @@ async def test_rotation_does_not_touch_a_master_mid_turn(world: World) -> None: await world.settle(conv, 1) +async def test_force_rotates_a_master_that_is_not_due(world: World) -> None: + conv = await world.conversations.create(kind="master", agent="a", origin="test") + rotation = Rotation(world.conversations, POLICY) + assert await rotation.tick() == [] + rotated = await rotation.tick(force="manual") + assert len(rotated) == 1 + assert rotated[0].external_id != conv.external_id + assert (await world.conversations.get(conv.external_id)).status == "closed" + assert len(await world.conversations.find(kind="master", status="open")) == 1 + + async def test_rotation_order_handout_close_marks_moves_and_new_day( world: World, ) -> None: