Files
roboco/tests/unit/gateway/test_delegate_sizing.py
T
Renn F 8affb283f5 feat(gateway): enable 2-devs-per-cell parallelism + split-before-claim sizing
- Intake / Main-PM / Cell-PM prompts: enumerate independently-shippable work
  units, inherit the breakdown down the chain, and dispatch independents in
  parallel (dependency order, never one-at-a-time).
- Raise the code-spine concurrency cap from 1 to 2 per parent (one per cell
  developer) so both devs build in parallel; keep the same-assignee guard and
  the planning/documentation cap at 1, plus the cross-team planning exemption.
- Split-before-claim: hard-block an egregiously-bundled code leaf at delegate
  time so the PM splits it before any dev claims it; nudge the moderate band
  in the delegate success envelope.
2026-06-14 04:34:02 +02:00

80 lines
2.7 KiB
Python

"""Split-before-claim: a code leaf must not bundle too many concerns.
A `code` subtask carrying more acceptance criteria than the hard cap bundles
multiple independent concerns into one leaf — QA can't pass a partial and
criteria get dropped. The gateway rejects it at delegate time so the PM splits
the bundle before any dev can claim it. Moderate bundling is allowed but flagged
in the success envelope (the nudge). `planning` briefs are exempt.
"""
from __future__ import annotations
from roboco.services.gateway.choreographer._impl import Choreographer, DelegateInputs
def _inputs(*, task_type: str, ac_count: int) -> DelegateInputs:
return DelegateInputs(
title="t",
description="d",
assigned_to="be-dev-1",
team="backend",
task_type=task_type,
nature="technical",
acceptance_criteria=[f"criterion {i}" for i in range(ac_count)],
)
def test_small_code_leaf_is_allowed() -> None:
"""A focused code leaf (<= hard cap) passes the sizing guard."""
assert (
Choreographer._delegate_sizing_guard(_inputs(task_type="code", ac_count=4))
is None
)
def test_code_leaf_at_hard_cap_is_allowed() -> None:
"""Exactly at the hard cap is still allowed; only strictly-above is blocked."""
cap = Choreographer._SIZING_HARD_AC_COUNT
assert (
Choreographer._delegate_sizing_guard(_inputs(task_type="code", ac_count=cap))
is None
)
def test_egregiously_bundled_code_leaf_is_rejected() -> None:
"""A code leaf above the hard cap is rejected with split guidance."""
cap = Choreographer._SIZING_HARD_AC_COUNT
env = Choreographer._delegate_sizing_guard(
_inputs(task_type="code", ac_count=cap + 4)
)
assert env is not None
body = env.as_dict()
assert body["error"] == "invalid_state", body
assert "Split this into smaller code subtasks" in (env.remediate or "")
def test_planning_brief_is_exempt_from_sizing() -> None:
"""planning subtasks (main_pm -> cell_pm) legitimately carry many criteria."""
assert (
Choreographer._delegate_sizing_guard(_inputs(task_type="planning", ac_count=20))
is None
)
def test_no_nudge_below_threshold() -> None:
assert Choreographer._sizing_hint(_inputs(task_type="code", ac_count=5)) is None
def test_nudge_in_moderate_band() -> None:
"""Above the nudge count and below the hard cap: allowed but flagged."""
hint = Choreographer._sizing_hint(_inputs(task_type="code", ac_count=7))
assert hint is not None
assert "7 acceptance criteria" in hint
assert "parallel" in hint
def test_no_nudge_for_planning() -> None:
assert (
Choreographer._sizing_hint(_inputs(task_type="planning", ac_count=20)) is None
)