mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
fix(gateway): let a dependent agent read its dependency via evidence
evidence is read-only, but the cross-agent ownership gate blocked a caller from inspecting a task its own work depends on (a frontend cell could not read the UX task it was waiting on). Exempt reads where the target is a dependency of a task assigned to the caller. Also dropped stale internal refs from the docstring.
This commit is contained in:
@@ -703,6 +703,17 @@ class ContentActions:
|
||||
context_briefing={},
|
||||
)
|
||||
|
||||
async def _is_caller_dependency(self, agent_id: UUID, task: Any) -> bool:
|
||||
"""True when ``task`` is a dependency of a task the caller is assigned to.
|
||||
|
||||
A dependent agent (e.g. a frontend cell waiting on a UX design task)
|
||||
must be able to inspect what it is blocked on; read-only evidence is the
|
||||
right tool, and the strict cross-agent ownership gate would otherwise
|
||||
reject it.
|
||||
"""
|
||||
assigned = await self.task.list_assigned_for_agent(agent_id)
|
||||
return any(task.id in (a.dependency_ids or []) for a in assigned)
|
||||
|
||||
async def evidence(
|
||||
self,
|
||||
*,
|
||||
@@ -711,28 +722,28 @@ class ContentActions:
|
||||
) -> Envelope:
|
||||
"""Inspect a task's PR diff, commits, files.
|
||||
|
||||
Fetches dev branch into the agent's workspace before diffing.
|
||||
Allows inspection when caller is assignee OR task is unassigned
|
||||
(post-handoff transient state) — strict ownership only blocks
|
||||
cross-agent inspection of an actively-owned task.
|
||||
Fetches the dev branch into the agent's workspace before diffing.
|
||||
Allows inspection when the caller is the assignee, the task is
|
||||
unassigned, the caller co-reviews a shared board task, or the task is a
|
||||
dependency the caller is waiting on — strict ownership only blocks
|
||||
snooping an unrelated, actively-owned task.
|
||||
|
||||
Task #154: ``files_changed`` and ``pr_diff_summary`` are pulled
|
||||
from git (against the branch's parent) — the authoritative source.
|
||||
Earlier versions hard-coded ``files_changed=[]`` and used
|
||||
``HEAD~1`` for the diff base, so QA / reviewers saw an empty
|
||||
change list and only the latest commit's delta even when the PR
|
||||
on GitHub had a multi-commit change set.
|
||||
``files_changed`` and ``pr_diff_summary`` are pulled from git (against
|
||||
the branch's parent — the authoritative source) rather than the latest
|
||||
commit's delta, so reviewers see the full multi-commit change set.
|
||||
"""
|
||||
t = await self.task.get(task_id)
|
||||
if t is None:
|
||||
return Envelope.not_found(message=f"task {task_id} not found")
|
||||
# A board co-reviewer (HoM inspecting a PO-assigned board task, or vice
|
||||
# versa) must be able to read the shared coordination task — the same
|
||||
# allowance the content verbs grant via co-review.
|
||||
# Reads are allowed for the assignee, an unassigned task, a board
|
||||
# co-reviewer of a shared coordination task, OR a caller whose own work
|
||||
# depends on this task. Strict ownership only blocks snooping an
|
||||
# unrelated, actively-owned task.
|
||||
if (
|
||||
t.assigned_to is not None
|
||||
and t.assigned_to != agent_id
|
||||
and not await self._board_may_co_review(agent_id, t)
|
||||
and not await self._is_caller_dependency(agent_id, t)
|
||||
):
|
||||
return _ownership_violation(task_id)
|
||||
if t.branch_name and t.work_session_id:
|
||||
|
||||
@@ -472,3 +472,41 @@ async def test_evidence_unassigned_task_allows_inspection() -> None:
|
||||
|
||||
env = await ca.evidence(agent_id=agent_id, task_id=task_id)
|
||||
assert env.error is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_evidence_allows_dependency_inspection() -> None:
|
||||
"""A caller whose own assigned task depends on the target may read it.
|
||||
|
||||
A frontend cell waiting on a UX design task must be able to inspect the
|
||||
dependency it is blocked on, even though another agent owns it.
|
||||
"""
|
||||
agent_id = uuid4()
|
||||
other_id = uuid4()
|
||||
dep_task_id = uuid4()
|
||||
target = MagicMock(
|
||||
id=dep_task_id,
|
||||
status="in_progress",
|
||||
assigned_to=other_id,
|
||||
branch_name="feature/ux_ui/abc",
|
||||
work_session_id=uuid4(),
|
||||
commits=[],
|
||||
pr_number=None,
|
||||
pr_url="",
|
||||
dev_notes="",
|
||||
acceptance_criteria_status=[],
|
||||
)
|
||||
callers_task = MagicMock(id=uuid4(), dependency_ids=[dep_task_id])
|
||||
task_svc = AsyncMock()
|
||||
task_svc.get.return_value = target
|
||||
task_svc.list_assigned_for_agent.return_value = [callers_task]
|
||||
git_svc = AsyncMock()
|
||||
git_svc.diff.return_value = ""
|
||||
git_svc.list_changed_files.return_value = []
|
||||
workspace_svc = AsyncMock()
|
||||
deps = _make_deps(task=task_svc, git=git_svc, workspace=workspace_svc)
|
||||
ca = ContentActions(deps)
|
||||
|
||||
env = await ca.evidence(agent_id=agent_id, task_id=dep_task_id)
|
||||
assert env.error is None
|
||||
task_svc.list_assigned_for_agent.assert_awaited()
|
||||
|
||||
Reference in New Issue
Block a user