mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
fix(content): keep coordination notes off dev_notes / quick_context
Two agent-authored fields were leaking non-developer content into the human note columns the panel renders: - apply_escalation appended '[ESCALATED] From X to Y\nReason: ...' to dev_notes (the developer's space). On a re-escalation loop a stuck cell PM grew one task's dev_notes to ~8KB across 5 escalations. It now writes a structured orchestration_markers['escalation'] record; the target still learns the reason from the escalate notification. - approve_and_start string-packed 'approve_and_start_notes:<text>' into quick_context (raw key:value soup). It now writes orchestration_markers['approve_and_start_notes'], leaving quick_context for the human ResumptionNote only. Adds typed marker accessors (get/set_escalation, get/set_approve_and_start_notes) and refactors _record_pr_review under the complexity bound by extracting _compose_review_body. Documents update_task_with_message as the legacy A2A-protocol log (dev_notes is intentional there, not pollution).
This commit is contained in:
@@ -91,22 +91,25 @@ async def test_reassigns_to_main_pm_and_keeps_pending(start_setup: dict) -> None
|
||||
assert out is not None
|
||||
assert out.assigned_to == start_setup["main_pm"].id
|
||||
assert out.status == TaskStatus.PENDING
|
||||
assert out.quick_context is not None
|
||||
assert "approve_and_start_notes:" in out.quick_context
|
||||
assert note in out.quick_context
|
||||
# The CEO note is a structured marker, not raw soup in quick_context.
|
||||
assert (out.orchestration_markers or {})["approve_and_start_notes"] == note
|
||||
assert "approve_and_start_notes:" not in (out.quick_context or "")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_audit_note_appends_to_existing_context(start_setup: dict) -> None:
|
||||
async def test_audit_note_preserves_context_and_stores_marker(
|
||||
start_setup: dict,
|
||||
) -> None:
|
||||
task = start_setup["mk"]()
|
||||
task.quick_context = "prior context"
|
||||
await start_setup["db"].flush()
|
||||
note = "Board signed off; ship it."
|
||||
out = await start_setup["svc"].approve_and_start(task.id, note)
|
||||
assert out is not None
|
||||
assert out.quick_context is not None
|
||||
assert "prior context" in out.quick_context
|
||||
assert f"approve_and_start_notes:{note}" in out.quick_context
|
||||
# An existing human ResumptionNote is preserved untouched...
|
||||
assert out.quick_context == "prior context"
|
||||
# ...and the CEO note lands in the markers, not appended to the context.
|
||||
assert (out.orchestration_markers or {})["approve_and_start_notes"] == note
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -1448,7 +1448,10 @@ async def test_apply_escalation_reassigns_and_blocks(
|
||||
assert task.status == TaskStatus.BLOCKED
|
||||
assert task.assigned_to == target.id
|
||||
assert task.blocker_raised_by == task_setup["agent_id"]
|
||||
assert "[ESCALATED]" in (task.dev_notes or "")
|
||||
# The escalation is a structured marker, NOT a developer note.
|
||||
assert not (task.dev_notes or "")
|
||||
esc = (task.orchestration_markers or {})["escalation"]
|
||||
assert esc == {"from": "dev-1", "to": "cell-pm", "reason": "external blocker"}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
Reference in New Issue
Block a user