fix(gateway): heartbeat on content-write success, single-claimant gate, progress soft-warn

commit()/progress()/note() now refresh last_heartbeat_at on the success
path (best-effort, suppressed), not only on rejection — an actively
writing agent no longer looks idle to the reaper between verb successes.

commit()/progress() verify the caller holds the active claim
(active_claimant_id), not merely the historical assigned_to, so a reaped
or handed-off assignee can no longer write onto a freed task; a non-holder
gets a not_authorized envelope with a clear remediate.

progress() with no plan_step on a task that has steps is accepted (product
decision for narrative mid-step updates) and logs a soft warning instead of
rejecting.
This commit is contained in:
Renn F
2026-06-03 18:44:33 +02:00
parent 61e80495c3
commit 2c96bd09f6
5 changed files with 415 additions and 26 deletions
@@ -78,6 +78,7 @@ async def test_commit_active_task_returned_must_be_caller_owned() -> None:
id=task_id,
status="in_progress",
assigned_to=agent_id,
active_claimant_id=agent_id,
branch_name="feature/backend/abc",
)
task_svc = AsyncMock()