mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
feat(content): anti-soup guard on the flow verbs' free-text
Extends structured-content enforcement from the content tools to every flow verb that carries agent free-text, closing the last hole where a dev/PM could pass word soup: i_am_blocked(reason), i_am_done(notes), submit_up/submit_root/complete(notes), escalate_up/escalate_to_ceo(reason), pass_review(notes), fail_review/pr_fail(issues), pr_pass(notes), i_documented(notes), delegate(title/description). Plans (i_will_plan / i_will_work_on) keep their existing >=150-char approach + sub_task gates and are skipped here so recovery re-entry with thin values still works. Shared helpers on the choreographer: _free_text_soup (bare envelope, list aware) and _soup_or_decision_env (folds the soup check into a verb's existing spec-gate return so no verb gains a return or tips the xenon bound). reject_trivial now also catches all-filler multi-token strings. base.md documents the broadened rule for agents.
This commit is contained in:
@@ -763,7 +763,7 @@ async def test_complete_rejects_non_pm_role() -> None:
|
||||
deps = _make_deps(task=task_svc)
|
||||
c = Choreographer(deps)
|
||||
|
||||
env = await c.complete(dev_id, task_id, notes="x")
|
||||
env = await c.complete(dev_id, task_id, notes="reviewed and approved")
|
||||
body = env.as_dict()
|
||||
assert body["error"] == "not_authorized"
|
||||
assert "cell_pm" in body["remediate"] and "main_pm" in body["remediate"]
|
||||
@@ -816,7 +816,7 @@ async def test_escalate_up_returns_invalid_state_when_target_lookup_fails() -> N
|
||||
deps = _make_deps(task=task_svc, journal=journal_svc)
|
||||
c = Choreographer(deps)
|
||||
|
||||
env = await c.escalate_up(pm_id, task_id, reason="x")
|
||||
env = await c.escalate_up(pm_id, task_id, reason="needs cross-cell coordination")
|
||||
body = env.as_dict()
|
||||
assert body["error"] == "invalid_state"
|
||||
assert "main-pm" in body["message"]
|
||||
@@ -841,7 +841,7 @@ async def test_escalate_up_blocks_without_journal_decision() -> None:
|
||||
deps = _make_deps(task=task_svc, journal=journal_svc)
|
||||
c = Choreographer(deps)
|
||||
|
||||
env = await c.escalate_up(pm_id, task_id, reason="x")
|
||||
env = await c.escalate_up(pm_id, task_id, reason="needs cross-cell coordination")
|
||||
body = env.as_dict()
|
||||
assert body["error"] == "tracing_gap"
|
||||
assert "journal:decision" in body["missing"]
|
||||
@@ -871,7 +871,7 @@ async def test_escalate_up_no_target_returns_invalid_state() -> None:
|
||||
deps = _make_deps(task=task_svc, journal=journal_svc)
|
||||
c = Choreographer(deps)
|
||||
|
||||
env = await c.escalate_up(pm_id, task_id, reason="x")
|
||||
env = await c.escalate_up(pm_id, task_id, reason="needs cross-cell coordination")
|
||||
body = env.as_dict()
|
||||
assert body["error"] == "invalid_state"
|
||||
|
||||
@@ -885,5 +885,5 @@ async def test_escalate_up_task_not_found() -> None:
|
||||
deps = _make_deps(task=task_svc)
|
||||
c = Choreographer(deps)
|
||||
|
||||
env = await c.escalate_up(pm_id, task_id, reason="x")
|
||||
env = await c.escalate_up(pm_id, task_id, reason="needs cross-cell coordination")
|
||||
assert env.as_dict()["error"] == "not_found"
|
||||
|
||||
Reference in New Issue
Block a user