mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
feat(gateway): substantive-plan gate — approach >=150 + real sub_task descriptions (#171)
Plans were vague because the gate accepted the bare minimum: PM approach >=20 chars and title-only sub_tasks. minimax wrote exactly the minimum. - IWillPlanRequest.approach min_length 20 -> 150 (kept in sync with _PM_APPROACH_MIN_LEN; the gate enforces it at the choreographer layer too so direct/MCP callers can't bypass the HTTP boundary). - New _thin_subtask_hint: every PM sub_task must have a title and a description >= _PM_SUBTASK_DESC_MIN_LEN (60) saying what the step does — each sub_task is both a delegate target AND a progress-checklist item, so a title alone is not a plan. - cell_pm/main_pm role prompts: explicit "the gate REJECTS thin plans" framing + concrete sub_task example + the new minimums. - Updated all affected test fixtures across the suite to use substantive approaches/descriptions; added thin-sub_task rejection coverage. Commit 1 of 3 for the plan/progress quality work (#171/#172/#173).
This commit is contained in:
@@ -237,11 +237,20 @@ async def test_i_will_plan_dispatches_to_choreographer() -> None:
|
||||
"task_id": _TASK_ID,
|
||||
"plan": "break into 3 subtasks for backend",
|
||||
"approach": (
|
||||
"Decompose into backend API slice, QA verification pass, "
|
||||
"and documentation update."
|
||||
"Decompose into a backend API slice that be-dev-1 owns end "
|
||||
"to end; QA reviews after the PR opens, documentation follows, "
|
||||
"then be-pm completes and submits up. Single-cell — no "
|
||||
"frontend or ux work; strict sequencing with no cross-cell "
|
||||
"dependencies for this planning task."
|
||||
),
|
||||
"sub_tasks": [
|
||||
{"title": "Backend API slice", "description": "Implement endpoint"}
|
||||
{
|
||||
"title": "Backend API slice",
|
||||
"description": (
|
||||
"be-dev-1 implements the endpoint with tests, commits "
|
||||
"with the task-id prefix, opens the leaf PR for QA."
|
||||
),
|
||||
}
|
||||
],
|
||||
},
|
||||
headers=_HEADERS,
|
||||
|
||||
@@ -208,12 +208,27 @@ async def test_i_will_plan_dispatches_to_choreographer() -> None:
|
||||
"task_id": _TASK_ID,
|
||||
"plan": "split into backend, frontend, ux cells",
|
||||
"approach": (
|
||||
"Three-cell decomposition: backend handles API, frontend "
|
||||
"handles UI integration, ux-ui handles design."
|
||||
"Three-cell decomposition: backend handles the API, frontend "
|
||||
"handles UI integration, ux-ui handles design. Sequenced so "
|
||||
"backend lands first, QA reviews each PR after it opens, "
|
||||
"documentation follows, then complete and submit up. No "
|
||||
"cross-cell dependencies beyond the stated ordering."
|
||||
),
|
||||
"sub_tasks": [
|
||||
{"title": "Backend cell", "description": "API implementation"},
|
||||
{"title": "Frontend cell", "description": "UI integration"},
|
||||
{
|
||||
"title": "Backend cell",
|
||||
"description": (
|
||||
"be-dev-1 implements the API endpoint and migration "
|
||||
"with tests, opens the leaf PR for QA."
|
||||
),
|
||||
},
|
||||
{
|
||||
"title": "Frontend cell",
|
||||
"description": (
|
||||
"fe-dev-1 wires the panel to the new endpoint with "
|
||||
"loading and error states, opens the leaf PR."
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
headers=_HEADERS,
|
||||
|
||||
@@ -19,7 +19,19 @@ _AGENT_ID = "00000000-0000-0000-0004-000000000001"
|
||||
_HEADERS = {"X-Agent-ID": _AGENT_ID, "X-Agent-Role": "main_pm"}
|
||||
_HTTP_UNPROCESSABLE = 422
|
||||
_HTTP_OK = 200
|
||||
_MIN_APPROACH_LEN = 20
|
||||
# #171: raised 20→150 — must stay in sync with IWillPlanRequest.approach
|
||||
# min_length and choreographer._impl._PM_APPROACH_MIN_LEN.
|
||||
_MIN_APPROACH_LEN = 150
|
||||
_GOOD_APPROACH = (
|
||||
"Single-cell decomposition for the git-workflow smoke test: be-pm owns "
|
||||
"the backend slice end to end — claim, branch, delegate the README edit "
|
||||
"to be-dev-1, sequence QA after the PR opens, then documentation, then "
|
||||
"complete and submit_up. Frontend and UX cells are unaffected."
|
||||
)
|
||||
_GOOD_SUBTASK_DESC = (
|
||||
"be-dev-1 creates the feature branch, prepends the smoke-test HTML "
|
||||
"comment above the README H1 leaving the rest untouched, commits, opens PR."
|
||||
)
|
||||
|
||||
|
||||
def _make_envelope(error: str, missing: list[str] | None = None) -> MagicMock:
|
||||
@@ -76,10 +88,7 @@ def test_i_will_plan_rejects_empty_subtasks_for_pm() -> None:
|
||||
json={
|
||||
"task_id": str(uuid4()),
|
||||
"plan": "Route to backend cell only",
|
||||
"approach": (
|
||||
"Single-cell decomposition: backend cell handles the "
|
||||
"smoke test end-to-end; frontend and ux unaffected."
|
||||
),
|
||||
"approach": _GOOD_APPROACH,
|
||||
"sub_tasks": [], # empty — gateway rejects for PM
|
||||
},
|
||||
)
|
||||
@@ -101,11 +110,8 @@ def test_i_will_plan_schema_accepts_rich_plan() -> None:
|
||||
req = IWillPlanRequest(
|
||||
task_id=uuid4(),
|
||||
plan="Route to backend",
|
||||
approach=(
|
||||
"Single-cell decomposition for the smoke test: be-pm handles "
|
||||
"git workflow validation end to end."
|
||||
),
|
||||
sub_tasks=[{"title": "Backend slice", "description": "Branch + edit + PR"}],
|
||||
approach=_GOOD_APPROACH,
|
||||
sub_tasks=[{"title": "Backend slice", "description": _GOOD_SUBTASK_DESC}],
|
||||
risks=[],
|
||||
open_questions=[],
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user