"""Unit tests — sprint commit proposal rankers (P6).""" from __future__ import annotations from steering.eval_context import SteeringEvalContext from steering.kernel.models import HorizonMarker, LifecycleContext, SteeringBinding from steering.proposals.sprint_commit import propose_sprint_commit from tenant_context import TenantContext def _ctx( *, backlog_items: list, work_cycles: list, actions: list | None = None, vocabulary: dict | None = None, ) -> SteeringEvalContext: binding = SteeringBinding( primary_method_key="continuous_product", composition_modifier="agile_iteration", next_work_strategy_key="agile_iteration", ) lifecycle = LifecycleContext( current_state="execution", current_state_label="Ausführung", slot_map={}, active_slots=(), operational_slots=(), ) horizon = HorizonMarker(kind="work_cycle", work_cycle_id="wc-1", work_cycle_title="S1") eval_ctx = SteeringEvalContext( tenant_ctx=TenantContext( user_id="u1", email="t@example.com", display_name="Test", portal_role="user", tenant_id="t1", tenant_slug="t", tenant_name="T", tenant_role="admin", actor_id=None, actor_type=None, session_token="test", capabilities=frozenset(), ), initiative_id="init-1", binding=binding, horizon=horizon, lifecycle=lifecycle, operating_context={ "steering_elements": ["work_cycle_scope", "backlog_epic_hierarchy"], "data_slices": ["backlog", "work_cycles"], "backlog_vocabulary": vocabulary or {"convertible_kinds": ["story", "bug", "issue"]}, }, ) eval_ctx._backlog_items = backlog_items eval_ctx._work_cycles = work_cycles eval_ctx._actions = actions or [] return eval_ctx def test_critical_story_can_rank_before_normal_bug(): proposals = propose_sprint_commit( _ctx( work_cycles=[{"id": "wc-1", "title": "Sprint 1", "status": "planned", "sort_order": 0}], backlog_items=[ {"id": "s1", "title": "Critical story", "item_kind": "story", "status": "accepted", "priority": "critical", "sort_order": 1}, {"id": "b1", "title": "Minor bug", "item_kind": "bug", "status": "accepted", "priority": "normal", "sort_order": 0}, ], ) ) assert proposals[0]["scope_id"] == "s1" assert proposals[0]["ranker_key"] == "heuristic_v0" assert any(f["code"] == "priority" for f in proposals[0]["factors"]) def test_dependency_blocked_bug_ranks_after_ready_story(): proposals = propose_sprint_commit( _ctx( work_cycles=[{"id": "wc-1", "title": "Sprint 1", "status": "planned", "sort_order": 0}], backlog_items=[ {"id": "s1", "title": "Ready story", "item_kind": "story", "status": "accepted", "priority": "normal", "sort_order": 1}, { "id": "b1", "title": "Blocked bug", "item_kind": "bug", "status": "accepted", "priority": "critical", "sort_order": 0, "parent_action_id": "a-feature", }, ], actions=[ {"id": "a-feature", "title": "Feature", "status": "in_progress", "work_cycle_id": None}, ], ) ) assert proposals[0]["scope_id"] == "s1" blocked = next(p for p in proposals if p["scope_id"] == "b1") assert blocked["dependency_blocked"] is True assert blocked["reason_code"] == "waiting_on_feature_action" def test_sprint_commit_empty_without_planable_cycle(): proposals = propose_sprint_commit( _ctx( work_cycles=[], backlog_items=[ {"id": "s1", "title": "Story", "item_kind": "story", "status": "accepted", "priority": "normal", "sort_order": 0}, ], ) ) assert proposals == []