mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
101 lines
3.7 KiB
Python
101 lines
3.7 KiB
Python
"""Smoke-5: get_journal_context_task_for_agent includes BLOCKED, PAUSED,
|
|||
|
|
NEEDS_REVISION so note/say/dm/notify auto-inject task_id while the agent
|
||
|
|
is stuck.
|
||
|
|
|
||
|
|
Original bug: get_active_task_for_agent filtered to DEV_ACTIVE statuses only.
|
||
|
|
PMs writing decisions during BLOCKED state got task_id=NULL on their journal
|
||
|
|
entries. The C8 tracing gate then never found the decisions and the agent
|
||
|
|
spiraled. Smoke-5 wrote 5 decisions, 8 reflections, 1 struggle — all with
|
||
|
|
task_id=NULL because the agent was stuck when journaling.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from unittest.mock import AsyncMock, MagicMock
|
||
|
|
from uuid import uuid4
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
from roboco.models.base import TaskStatus
|
||
|
|
from roboco.services.task import TaskService
|
||
|
|
|
||
|
|
|
||
|
|
def _service_with(execute_returns: object) -> TaskService:
|
||
|
|
session = MagicMock()
|
||
|
|
session.execute = AsyncMock(return_value=execute_returns)
|
||
|
|
return TaskService(session)
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_journal_context_returns_blocked_task() -> None:
|
||
|
|
"""A BLOCKED task is returned by the journal-context lookup."""
|
||
|
|
task = MagicMock(id=uuid4(), status=TaskStatus.BLOCKED)
|
||
|
|
result = MagicMock()
|
||
|
|
result.scalar_one_or_none.return_value = task
|
||
|
|
svc = _service_with(result)
|
||
|
|
found = await svc.get_journal_context_task_for_agent(uuid4())
|
||
|
|
assert found is task
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_journal_context_returns_paused_task() -> None:
|
||
|
|
"""A PAUSED task is returned by the journal-context lookup."""
|
||
|
|
task = MagicMock(id=uuid4(), status=TaskStatus.PAUSED)
|
||
|
|
result = MagicMock()
|
||
|
|
result.scalar_one_or_none.return_value = task
|
||
|
|
svc = _service_with(result)
|
||
|
|
found = await svc.get_journal_context_task_for_agent(uuid4())
|
||
|
|
assert found is task
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_journal_context_returns_needs_revision_task() -> None:
|
||
|
|
"""A NEEDS_REVISION task is returned so QA-rejected devs still get task_id."""
|
||
|
|
task = MagicMock(id=uuid4(), status=TaskStatus.NEEDS_REVISION)
|
||
|
|
result = MagicMock()
|
||
|
|
result.scalar_one_or_none.return_value = task
|
||
|
|
svc = _service_with(result)
|
||
|
|
found = await svc.get_journal_context_task_for_agent(uuid4())
|
||
|
|
assert found is task
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_journal_context_query_filters_by_journal_statuses() -> None:
|
||
|
|
"""The query's where clause uses _JOURNAL_CONTEXT_STATUSES, not _DEV_ACTIVE."""
|
||
|
|
result = MagicMock()
|
||
|
|
result.scalar_one_or_none.return_value = None
|
||
|
|
session = MagicMock()
|
||
|
|
session.execute = AsyncMock(return_value=result)
|
||
|
|
svc = TaskService(session)
|
||
|
|
agent_id = uuid4()
|
||
|
|
|
||
|
|
await svc.get_journal_context_task_for_agent(agent_id)
|
||
|
|
|
||
|
|
assert session.execute.await_count == 1
|
||
|
|
sent_query = session.execute.await_args.args[0]
|
||
|
|
rendered = str(sent_query.compile(compile_kwargs={"literal_binds": True}))
|
||
|
|
for s in ("blocked", "paused", "needs_revision", "in_progress", "claimed"):
|
||
|
|
assert s in rendered, (
|
||
|
|
f"Journal-context query missing status {s}. Rendered SQL: {rendered}"
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_dev_active_query_still_excludes_blocked() -> None:
|
||
|
|
"""The narrow get_active_task_for_agent stays narrow — commit() relies on it."""
|
||
|
|
result = MagicMock()
|
||
|
|
result.scalar_one_or_none.return_value = None
|
||
|
|
session = MagicMock()
|
||
|
|
session.execute = AsyncMock(return_value=result)
|
||
|
|
svc = TaskService(session)
|
||
|
|
|
||
|
|
await svc.get_active_task_for_agent(uuid4())
|
||
|
|
|
||
|
|
sent_query = session.execute.await_args.args[0]
|
||
|
|
rendered = str(sent_query.compile(compile_kwargs={"literal_binds": True}))
|
||
|
|
assert "'blocked'" not in rendered, (
|
||
|
|
"Dev-active query must NOT include BLOCKED — commit() would otherwise "
|
||
|
|
"allow commits from a blocked task."
|
||
|
|
)
|
||
|
|
assert "'paused'" not in rendered
|
||
|
|
assert "'needs_revision'" not in rendered
|