mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
- 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.
80 lines
2.7 KiB
Python
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
|
|
)
|